/
index.js
263 lines (226 loc) · 7.61 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
import { parse, isAfter, differenceInDays } from "date-fns";
import {
AVAILABLE,
AVAILABLE_REVISIONS_SELECT_UNRELEASED,
AVAILABLE_REVISIONS_SELECT_RECENT,
AVAILABLE_REVISIONS_SELECT_LAUNCHPAD
} from "../constants";
import { isInDevmode, getBuildId, isRevisionBuiltOnLauchpad } from "../helpers";
import { sortAlphaNum } from "../../../libs/channels";
// returns release history filtered by history filters
export function getFilteredReleaseHistory(state) {
const releases = state.releases;
const revisions = state.revisions;
const filters = state.history.filters;
return (
releases
// only releases of revisions (ignore closing channels)
.filter(release => release.revision)
// only releases in given architecture
.filter(release => {
return filters && filters.arch
? release.architecture === filters.arch
: true;
})
// only releases in given track
.filter(release => {
return filters && filters.track
? release.track === filters.track
: true;
})
// only releases in given risk
.filter(release => {
return filters && filters.risk ? release.risk === filters.risk : true;
})
// only releases without a branch, or a given branch
.filter(release => {
return filters && filters.branch
? release.branch === filters.branch
: true;
})
// only one latest release of every revision
.filter((release, index, all) => {
return all.findIndex(r => r.revision === release.revision) === index;
})
// map release history to revisions
.map(release => {
return {
...revisions[release.revision],
release
};
})
);
}
// returns list of selected revisions, to know which ones to render selected
export function getSelectedRevisions(state) {
if (state.channelMap[AVAILABLE]) {
return Object.values(state.channelMap[AVAILABLE]).map(
revision => revision.revision
);
}
return [];
}
// return selected revision for given architecture
export function getSelectedRevision(state, arch) {
if (state.channelMap[AVAILABLE]) {
return state.channelMap[AVAILABLE][arch];
}
}
// returns list of selected architectures
export function getSelectedArchitectures(state) {
if (state.channelMap[AVAILABLE]) {
return Object.keys(state.channelMap[AVAILABLE]);
}
return [];
}
// return true if there are any devmode revisions in the state
export function hasDevmodeRevisions(state) {
return Object.values(state.channelMap).some(archReleases => {
return Object.values(archReleases).some(isInDevmode);
});
}
// get channel map data updated with any pending releases
export function getPendingChannelMap(state) {
const { channelMap, pendingReleases } = state;
const pendingChannelMap = JSON.parse(JSON.stringify(channelMap));
// for each release
Object.keys(pendingReleases).forEach(releasedRevision => {
pendingReleases[releasedRevision].channels.forEach(channel => {
const revision = pendingReleases[releasedRevision].revision;
if (!pendingChannelMap[channel]) {
pendingChannelMap[channel] = {};
}
revision.architectures.forEach(arch => {
pendingChannelMap[channel][arch] = revision;
});
});
});
return pendingChannelMap;
}
// get all revisions ordered from newest (based on revsion id)
export function getAllRevisions(state) {
return Object.values(state.revisions).reverse();
}
// get all revisions not released to any channel yet
export function getUnreleasedRevisions(state) {
return getAllRevisions(state).filter(
revision => !revision.channels || revision.channels.length === 0
);
}
// get unreleased revisions not older then 7 days
export function getRecentRevisions(state) {
const interval = 1000 * 60 * 60 * 24 * 7; // 7 days
return getUnreleasedRevisions(state).filter(
r => Date.now() - new Date(r.created_at).getTime() < interval
);
}
// return list of revisions based on given selection value
export function getAvailableRevisionsBySelection(state, value) {
switch (value) {
case AVAILABLE_REVISIONS_SELECT_RECENT:
return getRecentRevisions(state);
case AVAILABLE_REVISIONS_SELECT_UNRELEASED:
return getUnreleasedRevisions(state);
case AVAILABLE_REVISIONS_SELECT_LAUNCHPAD:
return getLaunchpadRevisions(state);
default:
return getAllRevisions(state);
}
}
// return list of revisions based on current availableRevisionsSelect value
export function getFilteredAvailableRevisions(state) {
const { availableRevisionsSelect } = state;
return getAvailableRevisionsBySelection(state, availableRevisionsSelect);
}
// return list of revisions based on current availableRevisionsSelect value
// filtered by arch (can't be memoized)
export function getFilteredAvailableRevisionsForArch(state, arch) {
return getFilteredAvailableRevisions(state).filter(revision =>
revision.architectures.includes(arch)
);
}
// get list of architectures of uploaded revisions
export function getArchitectures(state) {
let archs = [];
getAllRevisions(state).forEach(revision => {
archs = archs.concat(revision.architectures);
});
// make archs unique and sorted
archs = archs.filter((item, i, ar) => ar.indexOf(item) === i);
return archs.sort();
}
export function getTracks(state) {
let tracks = [];
state.releases.map(t => t.track).forEach(track => {
// if we haven't saved it yet
if (tracks.indexOf(track) === -1) {
tracks.push(track);
}
});
return sortAlphaNum(tracks, "latest");
}
export function getBranches(state) {
let branches = [];
const { currentTrack } = state;
const now = parse(Date.now());
state.releases
.filter(t => t.branch && t.track === currentTrack)
.sort((a, b) => {
return isAfter(parse(b.when), parse(a.when));
})
.forEach(({ track, risk, branch, when, revision }) => {
const exists =
branches.filter(
b => b.track === track && b.risk === risk && b.branch === branch
).length > 0;
if (!exists) {
branches.push({
track,
risk,
branch,
revision,
when
});
}
});
return branches
.filter(b => {
return differenceInDays(now, parse(b.when)) <= 30;
})
.reverse();
}
// return true if there is a pending release in given channel for given arch
export function hasPendingRelease(state, channel, arch) {
const { channelMap } = state;
const pendingChannelMap = getPendingChannelMap(state);
// current revision to show (released or pending)
let currentRevision =
pendingChannelMap[channel] && pendingChannelMap[channel][arch];
// already released revision
let releasedRevision = channelMap[channel] && channelMap[channel][arch];
// check if there is a pending release in this cell
return (
currentRevision &&
(!releasedRevision ||
releasedRevision.revision !== currentRevision.revision)
);
}
export function getTrackRevisions({ channelMap }, track) {
const trackKeys = Object.keys(channelMap).filter(
trackName => trackName.indexOf(track) == 0
);
return trackKeys.map(trackName => channelMap[trackName]);
}
// return true if any revision has build-request-id attribute
export function hasBuildRequestId(state) {
return getAllRevisions(state).some(revision => getBuildId(revision));
}
// return revisions built by launchpad
export function getLaunchpadRevisions(state) {
return getAllRevisions(state).filter(isRevisionBuiltOnLauchpad);
}
export function getRevisionsFromBuild(state, buildId) {
return getAllRevisions(state).filter(
revision => getBuildId(revision) === buildId
);
}