Skip to content

Commit e6bd704

Browse files
authored
Merge pull request #2375 from Azure/master
Merge master into stable for release 2.11.0
2 parents aebe2b3 + 9334146 commit e6bd704

28 files changed

+566
-503
lines changed

.stylelintrc.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
"unit-case": "lower",
2626
"unit-no-unknown": true,
27-
"unit-blacklist": ["rem"],
27+
"unit-disallowed-list": ["rem"],
2828

2929
"value-no-vendor-prefix": true,
3030

CHANGELOG.md

+16
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
# 2.11.0
2+
3+
[All items](https://github.com/Azure/BatchExplorer/milestone/45?closed=1)
4+
5+
### feature
6+
7+
* Dynamically show/hide cloud services deprecation warning [\#2360](https://github.com/Azure/BatchExplorer/issues/2360)
8+
* Add fpga to vm size categories [\#2359](https://github.com/Azure/BatchExplorer/issues/2359)
9+
10+
### bug
11+
12+
* Fix resize error name wasn't being displayed properly [\#2361](https://github.com/Azure/BatchExplorer/issues/2361)
13+
* Fix accessibility issues regarding luminosity contrast, screen-reader, and keyboard shortcuts [\#2358](https://github.com/Azure/BatchExplorer/issues/2358)
14+
* Fix login with personal account [\#2344](https://github.com/Azure/BatchExplorer/issues/2344)
15+
* Fix user button tooltip showing as 'undefined' instead of username [\#2334](https://github.com/Azure/BatchExplorer/issues/2334)
16+
117
# 2.10.0
218

319
[All items](https://github.com/Azure/BatchExplorer/milestone/44?closed=1)

ThirdPartyNotices.txt

+287-301
Large diffs are not rendered by default.

package-lock.json

+146-106
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"name": "Microsoft Corporation",
1717
"email": "[email protected]"
1818
},
19-
"version": "2.10.0",
19+
"version": "2.11.0",
2020
"main": "build/client/main.prod.js",
2121
"scripts": {
2222
"ts": "ts-node --project tsconfig.node.json --files",
@@ -85,6 +85,7 @@
8585
"@types/inflection": "^1.5.28",
8686
"@types/jasmine": "^3.5.12",
8787
"@types/js-yaml": "^3.12.5",
88+
"@types/keytar": "^4.4.2",
8889
"@types/luxon": "^1.24.3",
8990
"@types/node": "12.12.21",
9091
"@types/node-fetch": "^2.5.7",
@@ -173,11 +174,10 @@
173174
"@angular/platform-browser-dynamic": "^9.1.12",
174175
"@angular/platform-server": "^9.1.12",
175176
"@angular/router": "^9.1.12",
176-
"@azure/msal-node": "^1.0.1",
177+
"@azure/msal-node": "^1.3.0",
177178
"@azure/storage-blob": "^10.5.0",
178-
"@types/keytar": "^4.4.2",
179179
"applicationinsights": "^1.8.5",
180-
"azure-storage": "^2.10.3",
180+
"azure-storage": "^2.10.4",
181181
"chart.js": "^2.9.3",
182182
"chokidar": "^3.4.3",
183183
"commander": "^2.20.3",

python/requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
websockets==7.0
1+
websockets==9.1
22
pylint==2.3.0
33
azure-batch-extensions==7.0.0
44
pyinstaller==3.6

scripts/lca/generate-third-party.ts

+14-8
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const defaultThirdPartyNoticeOptions: ThirdPartyNoticeOptions = {
1515
const thirdPartyNoticeFile = path.join(Constants.root, "ThirdPartyNotices.txt");
1616

1717
const output: string[] = [];
18-
const gitUrlRegex = /(?:git|ssh|https?|git@[-\w.]+):(\/\/[-\w.]+\/)?(.*?)(\.git)?(\/?|\#[-\d\w._]+?)$/;
18+
const gitUrlRegex = /(?:git|ssh|https?|git@[-\w.]+):(\/\/[-\w@.]+\/)?(.*?)(\.git)?(\/?|\#[-\d\w._]+?)$/;
1919
const repoNameRegex = /https?:\/\/github\.com\/(.*)/;
2020
const innerSeparator = "-".repeat(60);
2121
const outerSeparator = "=".repeat(60);
@@ -86,7 +86,6 @@ function listDependencies(): string[] {
8686
function loadDependency(name: string) {
8787
const contents = fs.readFileSync(`node_modules/${name}/package.json`).toString();
8888
const dependency = JSON.parse(contents);
89-
9089
const repoUrl = getRepoUrl(dependency);
9190
const url = dependency.homepage || repoUrl;
9291
return {
@@ -120,16 +119,23 @@ function getRepoName(repoUrl: string | null): string | null {
120119
return value.split("/").slice(0, 2).join("/");
121120
}
122121

123-
function loadLicense(repoUrl: string | null): Promise<any> {
122+
function loadLicense(repoUrl: string | null, anonymous = false): Promise<any> {
124123
const repoName = getRepoName(repoUrl);
125-
return fetch(`https://api.github.com/repos/${repoName}/license`, {
126-
headers: {
127-
Authorization: `token ${process.env.GH_TOKEN}`,
128-
},
129-
}).then((res) => {
124+
const licenseUrl = `https://api.github.com/repos/${repoName}/license`;
125+
const headers = anonymous ? {} : { Authorization: `token ${process.env.GH_TOKEN}`}
126+
127+
return fetch(licenseUrl, {headers}).then((res) => {
128+
/** Will look up default license if cannot find a license */
129+
if (!anonymous && res.status === 403) {
130+
console.warn(`Access denied, retrying request anonymously. Url: ${licenseUrl}`);
131+
return loadLicense(repoUrl, anonymous = true);
132+
} else if (res.status >= 300 && res.status != 404) {
133+
throw new Error(`Response status ${res.status} ${res.statusText} with url: ${licenseUrl}`);
134+
}
130135
return res.json();
131136
}).catch((error) => {
132137
console.error(`Error loading license for ${repoName}`, error);
138+
process.exit(1)
133139
});
134140
}
135141

scripts/publish/publish.ts

+42-26
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {
77
createIssue, createPullRequest, getMilestone, githubToken, listMilestoneIssues, listPullRequests,
88
} from "./github-api";
99

10+
const MAIN_BRANCH = "master";
11+
1012
const root = path.resolve(path.join(__dirname, "../.."));
1113
const allMessages: string[] = [];
1214
const repoName = "Azure/BatchExplorer";
@@ -54,57 +56,71 @@ function checkGithubToken() {
5456
/**
5557
* This goes back to master and pull
5658
*/
57-
async function gotoMaster() {
58-
await run("git checkout master");
59+
async function gotoMainBranch() {
60+
await run(`git checkout ${MAIN_BRANCH}`);
5961
await run("git pull");
60-
success("Checkout to master branch and pulled latest");
62+
success(`Checkout to ${MAIN_BRANCH} branch and pulled latest`);
6163
}
6264

63-
async function loadMillestone(millestoneId: number) {
64-
return getMilestone(repoName, millestoneId);
65+
async function loadMilestone(milestoneId: number) {
66+
return getMilestone(repoName, milestoneId);
6567
}
6668

6769
async function getCurrentBranch(): Promise<string> {
6870
const { stdout } = await run(`git symbolic-ref --short -q HEAD`);
6971
return stdout.trim();
7072
}
7173

72-
function getMillestoneId() {
74+
function getMilestoneId() {
7375
if (process.argv.length < 3) {
74-
throw new Error("No millestone id was provided.");
76+
throw new Error("No milestone id was provided.");
7577
}
7678
return parseInt(process.argv[2], 10);
7779
}
7880

7981
async function confirmVersion(version: string) {
8082
return new Promise((resolve, reject) => {
81-
ask(`Up program to be version ${version} (From millestone title) [Y/n]`, true, (ok) => {
83+
ask(`Up program to be version ${version} (From milestone title) [Y/n]`, true, (ok) => {
8284
if (ok) {
8385
success(`A new release for version ${version} will be prepared`);
8486
resolve(null);
8587
} else {
86-
reject(new Error("Millestone version wasn't confirmed. Please change millestone title"));
88+
reject(new Error("milestone version wasn't confirmed. Please change milestone title"));
8789
}
8890
});
8991
});
9092
}
9193

94+
function calcNextVersion(version: string) {
95+
const match = /^(\d+\.)(\d+)(\.\d+)$/.exec(version);
96+
return `${match[1]}${parseInt(match[2], 10) + 1}${match[3]}`;
97+
}
98+
9299
function getPreparationBranchName(version: string) {
93100
return `release/prepare-${version}`;
94101
}
95102

96103
async function switchToNewBranch(branchName: string) {
97-
await run(`git checkout -b ${branchName}`);
104+
await run(`git checkout -B ${branchName}`);
98105
success(`Created a new branch ${branchName}`);
99106
}
100107

101108
async function bumpVersion(version) {
102-
await run(`npm version --no-git-tag-version --allow-same-version ${version}`);
103-
success(`Updated version in package.json to ${version}`);
109+
const currentBranch = await getCurrentBranch();
110+
const nextVersion = calcNextVersion(version);
111+
const bumpBranch = `release/bump-${nextVersion}`;
112+
await gotoMainBranch();
113+
await switchToNewBranch(bumpBranch);
114+
await run(`npm version --no-git-tag-version --allow-same-version ${nextVersion}`);
115+
116+
await run(`git commit -am "Bump version to ${nextVersion}"`);
117+
await run(`git push origin ${bumpBranch}`);
118+
await run(`git checkout "${currentBranch}"`);
119+
success(`Updated version in package.json to ${nextVersion} (branch: ${bumpBranch})`);
104120
}
105121

106-
async function updateChangeLog(version, millestoneId) {
107-
const { stdout } = await run(`gh-changelog-gen --repo ${repoName} ${millestoneId} --formatter markdown`);
122+
async function updateChangeLog(version, milestoneId) {
123+
const { stdout } = await run(`gh-changelog-gen --repo ${repoName} ${milestoneId} --formatter markdown`);
108124
const changelogFile = path.join(root, "CHANGELOG.md");
109125
const changelogContent = fs.readFileSync(changelogFile);
110126

@@ -129,14 +145,14 @@ async function push(branchName: string) {
129145
await run(`git push --set-upstream origin ${branchName}`);
130146
}
131147

132-
async function createIssueIfNot(millestoneId, version) {
148+
async function createIssueIfNot(milestoneId, version) {
133149
const title = `Prepare for release of version ${version}`;
134-
const issues = await listMilestoneIssues(repoName, millestoneId);
150+
const issues = await listMilestoneIssues(repoName, milestoneId);
135151
let issue = issues.filter(x => x.title === title)[0];
136152
if (issue) {
137153
success(`Issue was already created earlier ${issue.html_url}`);
138154
} else {
139-
issue = await createIssue(repoName, title, newIssueBody, millestoneId);
155+
issue = await createIssue(repoName, title, newIssueBody, milestoneId);
140156
success(`Created a new issue ${issue.html_url}`);
141157
}
142158
return issue;
@@ -166,27 +182,27 @@ async function buildApp() {
166182

167183
async function startPublish() {
168184
checkGithubToken();
169-
const millestoneId = getMillestoneId();
170-
const millestone = await loadMillestone(millestoneId);
171-
if (!millestone.title && millestone["message"]) {
172-
throw new Error(`Error fetching milestone: ${millestone["message"]}`);
185+
const milestoneId = getMilestoneId();
186+
const milestone = await loadMilestone(milestoneId);
187+
if (!milestone.title && milestone["message"]) {
188+
throw new Error(`Error fetching milestone: ${milestone["message"]}`);
173189
}
174-
const version = millestone.title;
190+
const version = milestone.title;
175191
await confirmVersion(version);
176192
const releaseBranch = getPreparationBranchName(version);
177193
const branch = await getCurrentBranch();
178194
if (branch !== releaseBranch) {
179-
await gotoMaster();
195+
await gotoMainBranch();
180196
await switchToNewBranch(releaseBranch);
181197
}
182-
await bumpVersion(version);
183-
await updateChangeLog(version, millestoneId);
198+
await updateChangeLog(version, milestoneId);
184199
await updateThirdParty();
185200
await commitChanges();
186201
await push(releaseBranch);
187-
const issue = await createIssueIfNot(millestoneId, version);
202+
const issue = await createIssueIfNot(milestoneId, version);
188203
await createPullrequestIfNot(version, releaseBranch, issue);
189204
await buildApp();
205+
await bumpVersion(version);
190206
}
191207

192208
startPublish().then(() => {

src/@batch-flask/core/data-store/user-specific-data-store/user-specific-data-store.spec.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@ describe("UserSpecificDataStore", () => {
2929

3030
expect(spy).not.toHaveBeenCalled();
3131

32-
userServiceSpy.currentUser.next({ unique_name: "[email protected]" });
32+
userServiceSpy.currentUser.next({ username: "[email protected]" });
3333
});
3434

3535
describe("when the user is loaded", () => {
3636
beforeEach(() => {
37-
userServiceSpy.currentUser.next({ unique_name: "[email protected]" });
37+
userServiceSpy.currentUser.next({ username: "[email protected]" });
3838
});
3939

4040
it("defaults to null when there is no value", async () => {
@@ -85,7 +85,7 @@ describe("UserSpecificDataStore", () => {
8585
});
8686

8787
it("it gets value for the new user when switching", async () => {
88-
userServiceSpy.currentUser.next({ unique_name: "[email protected]" });
88+
userServiceSpy.currentUser.next({ username: "[email protected]" });
8989

9090
expect(await store.getItem("key-1")).toEqual("my-value-2");
9191
expect(await store.getItem("key-2")).toEqual(null);

src/@batch-flask/core/data-store/user-specific-data-store/user-specific-data-store.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { GlobalStorage } from "../global-storage";
88
export const USER_SERVICE = "USER_SERVICE";
99

1010
export interface User {
11-
unique_name: string;
11+
username: string;
1212
}
1313

1414
export interface UserService {
@@ -34,7 +34,7 @@ export class UserSpecificDataStore implements DataStore, OnDestroy {
3434
this._currentUser = this.userService.currentUser.pipe(
3535
takeUntil(this._destroy),
3636
filter(isNotNullOrUndefined),
37-
map(x => x.unique_name),
37+
map(x => x.username),
3838
publishReplay(1),
3939
refCount(),
4040
);

src/@batch-flask/ui/buttons/button.component.spec.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { Component, DebugElement, NO_ERRORS_SCHEMA } from "@angular/core";
22
import { ComponentFixture, TestBed } from "@angular/core/testing";
3-
import { MatTooltip } from "@angular/material/tooltip";
43
import { By } from "@angular/platform-browser";
54
import { NoopAnimationsModule } from "@angular/platform-browser/animations";
65
import { MaterialModule } from "@batch-flask/core";
@@ -54,8 +53,7 @@ describe("ButtonComponent", () => {
5453

5554
it("Should have the tooltip specified with title", () => {
5655
const el = de.query(By.css(".action-btn"));
57-
const tooltip = el.injector.get(MatTooltip);
58-
expect(tooltip.message).toBe("Stop");
56+
expect(el.nativeElement.title).toBe("Stop");
5957
});
6058

6159
it("should change color", () => {

src/@batch-flask/ui/buttons/button.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<div class="action-btn" [ngClass]="type" [matTooltip]="tooltipTitle" [matTooltipPosition]="tooltipPosition">
1+
<div class="action-btn" [ngClass]="type" title="{{tooltipTitle}}">
22
<div [class.hide]="status !== SubmitStatus.Idle" class="label">
33
<i [class]="icon"></i>
44
<ng-content></ng-content>

src/@batch-flask/ui/buttons/refresh-btn/refresh-btn.component.ts

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export class RefreshButtonComponent implements OnDestroy {
5959
@autobind()
6060
public onClick() {
6161
this.status = RefreshStatus.Refreshing;
62+
this.liveAnnouncer.announce("Refreshing in progress");
6263
this._refreshSub = this.refresh().subscribe(
6364
() => {
6465
this.status = RefreshStatus.Succeeded;

src/@batch-flask/ui/property-list/table-property/table-property.component.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ let idCounter = 0;
3838
@Component({
3939
selector: "bl-tp-cell",
4040
template: `
41-
<div class="cell-value">
41+
<div class="cell-value" aria-keyshortcuts="Enter Space">
4242
<ng-container *ngIf="!useContent">{{value}}</ng-container>
4343
<ng-content *ngIf="useContent"></ng-content>
4444
</div>

src/@batch-flask/ui/table/table.scss

-1
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,6 @@ bl-table {
174174

175175
.sort-icon {
176176
margin-left: 3px;
177-
color: $main-background;
178177
}
179178

180179
&:hover:not(.sorting) > .sort-icon {

src/app/components/layout/main-navigation/profile-button/profile-button.component.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ describe("ProfileButtonComponent", () => {
7979
it("shows the current user info in tooltip", () => {
8080
authServiceSpy.currentUser.next({
8181
name: "Some Name",
82-
unique_name: "[email protected]",
82+
username: "[email protected]",
8383
});
8484
fixture.detectChanges();
8585
const tooltip: MatTooltip = clickableEl.injector.get(MatTooltip);

src/app/components/layout/main-navigation/profile-button/profile-button.component.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@ export class ProfileButtonComponent implements OnDestroy, OnInit {
5353
private fs: FileSystemService,
5454
private router: Router) {
5555

56-
authService.currentUser.pipe(takeUntil(this._destroy)).subscribe((user) => {
56+
authService.currentUser.pipe(takeUntil(this._destroy)).subscribe(user => {
5757
if (user) {
58-
this.currentUserName = `${user.name} (${user.unique_name})`;
58+
this.currentUserName = `${user.name} (${user.username})`;
5959
} else {
6060
this.currentUserName = "";
6161
}

src/app/components/pool/action/add/pool-create-basic-dialog.component.ts

+5
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ export class PoolCreateBasicDialogComponent extends DynamicForm<Pool, PoolCreate
3333
public get virtualMachineConfiguration() {
3434
return this._osControl.value && this._osControl.value.virtualMachineConfiguration;
3535
}
36+
37+
public get cloudServiceConfiguration() {
38+
return this._osControl.value && this._osControl.value.cloudServiceConfiguration;
39+
}
40+
3641
public osSource: PoolOsSources = PoolOsSources.IaaS;
3742
public osType: "linux" | "windows" = "linux";
3843
public NodeFillType = NodeFillType;

0 commit comments

Comments
 (0)