Skip to content

Commit ec46a86

Browse files
authored
Merge pull request #1226 from topcoder-platform/develop
[PROD] Milestone Management
2 parents b1f397e + 2cd8f6b commit ec46a86

File tree

41 files changed

+4226
-58
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+4226
-58
lines changed

.circleci/config.yml

Lines changed: 95 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,44 @@
1-
version: 2
1+
version: 2.1
2+
parameters:
3+
run_basedeployment:
4+
default: true
5+
type: boolean
6+
run_smoketesting:
7+
default: false
8+
type: boolean
9+
210
defaults: &defaults
311
docker:
412
- image: circleci/python:2.7-stretch-browsers
13+
14+
test_defaults: &test_defaults
15+
docker:
16+
- image: docker:17.11.0-ce-git
17+
518
install_dependency: &install_dependency
619
name: Installation of build and deployment dependencies.
720
command: |
821
sudo apt install jq
922
sudo pip install awscli --upgrade
1023
sudo pip install docker-compose
24+
25+
install_test_dependency: &install_test_dependency
26+
name: Installation of build and deployment dependencies.
27+
command: |
28+
apk update
29+
apk add --no-cache bash openssl curl
30+
apk upgrade
31+
apk add --no-cache jq py-pip sudo
32+
sudo pip install awscli --upgrade
33+
1134
install_deploysuite: &install_deploysuite
1235
name: Installation of install_deploysuite.
1336
command: |
1437
git clone --branch v1.4 https://github.com/topcoder-platform/tc-deploy-scripts ../buildscript
1538
cp ./../buildscript/master_deploy.sh .
1639
cp ./../buildscript/buildenv.sh .
1740
cp ./../buildscript/awsconfiguration.sh .
41+
1842
restore_cache_settings_for_build: &restore_cache_settings_for_build
1943
key: docker-node-modules-28-10-2020-{{ checksum "package-lock.json" }}
2044

@@ -35,7 +59,7 @@ builddeploy_steps: &builddeploy_steps
3559
./buildenv.sh -e $DEPLOY_ENV -b ${LOGICAL_ENV}-${APPNAME}-buildvar
3660
echo awsenvconf >.dockerignore
3761
echo buildenvvar >>.dockerignore
38-
- run:
62+
- run:
3963
name: "building image"
4064
command: |
4165
source buildenvvar
@@ -48,7 +72,35 @@ builddeploy_steps: &builddeploy_steps
4872
./buildenv.sh -e $DEPLOY_ENV -b ${LOGICAL_ENV}-${APPNAME}-deployvar
4973
source buildenvvar
5074
./master_deploy.sh -d ECS -e $DEPLOY_ENV -t latest -s ${LOGICAL_ENV}-global-appvar,${LOGICAL_ENV}-${APPNAME}-appvar -i ${APPNAME}
75+
curl --request POST \
76+
--url https://circleci.com/api/v2/project/github/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/pipeline \
77+
--header "Circle-Token: ${CIRCLE_TOKEN}" \
78+
--header 'content-type: application/json' \
79+
--data '{"branch":"'"$CIRCLE_BRANCH"'","parameters":{"run_smoketesting":true, "run_basedeployment": false}}'
5180
81+
# Automated Smoke Testing
82+
smoke_testing: &smoke_testing
83+
# Initialization.
84+
- checkout
85+
- setup_remote_docker
86+
- run: *install_test_dependency
87+
- run: *install_deploysuite
88+
# Restoration of node_modules from cache.
89+
- restore_cache: *restore_cache_settings_for_build
90+
- run:
91+
name: "configuring environment"
92+
command: |
93+
./awsconfiguration.sh $DEPLOY_ENV
94+
./buildenv.sh -e $DEPLOY_ENV -b ${LOGICAL_ENV}-${APPNAME}-buildvar
95+
- run:
96+
name: "Run automation"
97+
no_output_timeout: 20m
98+
command: |
99+
source awsenvconf
100+
source buildenvvar
101+
./test-automation/smoketest.sh
102+
- store_artifacts:
103+
path: ./test-automation/test-results
52104

53105
jobs:
54106
# Build & Deploy against development backend
@@ -59,34 +111,69 @@ jobs:
59111
LOGICAL_ENV: "dev"
60112
NODE_ENV: "development"
61113
BABEL_ENV: "development"
62-
APPNAME: "challenge-engine-ui"
114+
APPNAME: "challenge-engine-ui"
63115
steps: *builddeploy_steps
64116

65117
"build-prod":
66118
<<: *defaults
67119
environment:
68120
DEPLOY_ENV: "PROD"
69-
LOGICAL_ENV: "prod"
121+
LOGICAL_ENV: "prod"
70122
NODE_ENV: "production"
71123
BABEL_ENV: "production"
72-
APPNAME: "challenge-engine-ui"
124+
APPNAME: "challenge-engine-ui"
73125
steps: *builddeploy_steps
74126

127+
"smoke-testing-dev":
128+
<<: *test_defaults
129+
environment:
130+
DEPLOY_ENV: "DEV"
131+
LOGICAL_ENV: "dev"
132+
APPNAME: "challenge-engine-ui"
133+
steps: *smoke_testing
134+
135+
"smoke-testing-prod":
136+
<<: *test_defaults
137+
environment:
138+
DEPLOY_ENV: "PROD"
139+
LOGICAL_ENV: "prod"
140+
APPNAME: "challenge-engine-ui"
141+
steps: *smoke_testing
142+
75143
workflows:
76144
version: 2
77145
build:
146+
when: << pipeline.parameters.run_basedeployment >>
78147
jobs:
79148
# Development builds are executed on "develop" branch only.
80149
- "build-dev":
81150
context : org-global
82-
filters:
151+
filters: &filters-dev
83152
branches:
84-
only: ['develop', 'feature/bug-bash-july']
153+
only: ['develop', 'feature/linking-challenge-milestone']
85154

86155
# Production builds are exectuted only on tagged commits to the
87156
# master branch.
88157
- "build-prod":
89158
context : org-global
90-
filters:
159+
filters: &filters-prod
91160
branches:
92161
only: master
162+
163+
Smoke Testing:
164+
when: << pipeline.parameters.run_smoketesting >>
165+
jobs:
166+
- Hold [Smoke-Testing]:
167+
type: approval
168+
- smoke-testing-dev:
169+
context : org-global
170+
requires:
171+
- Hold [Smoke-Testing]
172+
filters:
173+
<<: *filters-dev
174+
- smoke-testing-prod:
175+
context : org-global
176+
requires:
177+
- Hold [Smoke-Testing]
178+
filters:
179+
<<: *filters-prod

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
33

44
# dependencies
5-
/node_modules
5+
node_modules
66
/.pnp
77
.pnp.js
88
.idea
@@ -27,3 +27,7 @@ yarn-error.log*
2727
*.env
2828

2929
*.vscode
30+
31+
# e2e test case
32+
test-automation/temp
33+
test-automation/test-results

src/actions/challenges.js

Lines changed: 71 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import {
4949
LOAD_CHALLENGE_RESOURCES
5050
} from '../config/constants'
5151
import { loadProject } from './projects'
52+
import { removeChallengeFromPhaseProduct, saveChallengeAsPhaseProduct } from '../services/projects'
5253

5354
/**
5455
* Member challenges related redux actions
@@ -203,16 +204,34 @@ export function loadGroupDetails (groupIds) {
203204
*
204205
* @param {String} challengeId challenge id
205206
* @param {Object} challengeDetails challenge data
206-
*
207+
* @param {String} projectId project id
207208
* @returns {Promise<{ type: string, challengeDetails: object }>} action object
208209
*/
209-
export function updateChallengeDetails (challengeId, challengeDetails) {
210+
export function updateChallengeDetails (challengeId, challengeDetails, projectId) {
210211
return async (dispatch) => {
211212
dispatch({
212213
type: UPDATE_CHALLENGE_DETAILS_PENDING
213214
})
214215

215-
return updateChallenge(challengeId, challengeDetails).then((challenge) => {
216+
const milestoneId = challengeDetails.milestoneId
217+
// Check if milestone is deleted or updated
218+
const hasMilestone = _.has(challengeDetails, 'milestoneId')
219+
220+
if (hasMilestone) {
221+
delete challengeDetails.milestoneId
222+
}
223+
return updateChallenge(challengeId, challengeDetails).then(async challenge => {
224+
if (hasMilestone) {
225+
if (milestoneId && milestoneId !== -1) {
226+
await saveChallengeAsPhaseProduct(projectId, milestoneId, challengeId)
227+
challenge.milestoneId = milestoneId
228+
} else {
229+
await removeChallengeFromPhaseProduct(projectId, challengeId)
230+
challenge.milestoneId = milestoneId
231+
}
232+
}
233+
return challenge
234+
}).then((challenge) => {
216235
return dispatch({
217236
type: UPDATE_CHALLENGE_DETAILS_SUCCESS,
218237
challengeDetails: challenge
@@ -231,26 +250,39 @@ export function updateChallengeDetails (challengeId, challengeDetails) {
231250
* Create a new challenge
232251
*
233252
* @param {Object} challengeDetails challenge data
253+
* @param {String} projectId project id
234254
*
235255
* @returns {Promise<{ type: string, challengeDetails: object }>} action object
236256
*/
237-
export function createChallenge (challengeDetails) {
257+
export function createChallenge (challengeDetails, projectId) {
258+
console.log(challengeDetails)
238259
return async (dispatch) => {
239260
dispatch({
240261
type: CREATE_CHALLENGE_PENDING
241262
})
242-
243-
return createChallengeAPI(challengeDetails).then((challenge) => {
244-
return dispatch({
245-
type: CREATE_CHALLENGE_SUCCESS,
246-
challengeDetails: challenge
263+
const milestoneId = challengeDetails.milestoneId
264+
if (milestoneId) {
265+
delete challengeDetails.milestoneId
266+
}
267+
return createChallengeAPI(challengeDetails)
268+
.then(async challenge => {
269+
if (milestoneId && milestoneId !== -1) {
270+
await saveChallengeAsPhaseProduct(projectId, milestoneId, challenge.id, true)
271+
challenge.milestoneId = milestoneId
272+
}
273+
return challenge
247274
})
248-
}).catch((e) => {
249-
dispatch({
250-
type: CREATE_CHALLENGE_FAILURE,
251-
error: e
275+
.then((challenge) => {
276+
return dispatch({
277+
type: CREATE_CHALLENGE_SUCCESS,
278+
challengeDetails: challenge
279+
})
280+
}).catch((e) => {
281+
dispatch({
282+
type: CREATE_CHALLENGE_FAILURE,
283+
error: e
284+
})
252285
})
253-
})
254286
}
255287
}
256288

@@ -261,16 +293,32 @@ export function createChallenge (challengeDetails) {
261293
*
262294
* @param {String} challengeId challenge id
263295
* @param {Object} partialChallengeDetails partial challenge data
264-
*
296+
* @param {String} projectId project id
265297
* @returns {Promise<{ type: string, challengeDetails: object }>} action object
266298
*/
267-
export function partiallyUpdateChallengeDetails (challengeId, partialChallengeDetails) {
299+
export function partiallyUpdateChallengeDetails (challengeId, partialChallengeDetails, projectId) {
268300
return async (dispatch) => {
269301
dispatch({
270302
type: UPDATE_CHALLENGE_DETAILS_PENDING
271303
})
272-
273-
return patchChallenge(challengeId, partialChallengeDetails).then((challenge) => {
304+
const milestoneId = partialChallengeDetails.milestoneId
305+
// Check if milestone is deleted or updated
306+
const hasMilestone = _.has(partialChallengeDetails, 'milestoneId')
307+
if (hasMilestone) {
308+
delete partialChallengeDetails.milestoneId
309+
}
310+
return patchChallenge(challengeId, partialChallengeDetails).then(async challenge => {
311+
if (hasMilestone) {
312+
if (milestoneId && milestoneId !== -1) {
313+
await saveChallengeAsPhaseProduct(projectId, milestoneId, challenge.id)
314+
challenge.milestoneId = milestoneId
315+
} else {
316+
await removeChallengeFromPhaseProduct(projectId, challengeId)
317+
challenge.milestoneId = milestoneId
318+
}
319+
}
320+
return challenge
321+
}).then((challenge) => {
274322
return dispatch({
275323
type: UPDATE_CHALLENGE_DETAILS_SUCCESS,
276324
challengeDetails: challenge
@@ -284,13 +332,15 @@ export function partiallyUpdateChallengeDetails (challengeId, partialChallengeDe
284332
}
285333
}
286334

287-
export function deleteChallenge (challengeId) {
335+
export function deleteChallenge (challengeId, projectId) {
288336
return async (dispatch) => {
289337
dispatch({
290338
type: DELETE_CHALLENGE_PENDING
291339
})
292-
293-
return deleteChallengeAPI(challengeId).then((challenge) => {
340+
return deleteChallengeAPI(challengeId).then(async challenge => {
341+
await removeChallengeFromPhaseProduct(projectId, challengeId)
342+
return challenge
343+
}).then((challenge) => {
294344
return dispatch({
295345
type: DELETE_CHALLENGE_SUCCESS,
296346
challengeDetails: challenge

src/actions/projects.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import {
22
LOAD_PROJECT_BILLING_ACCOUNT,
33
LOAD_CHALLENGE_MEMBERS_SUCCESS,
4-
LOAD_PROJECT_DETAILS
4+
LOAD_PROJECT_DETAILS,
5+
LOAD_PROJECT_PHASES
56
} from '../config/constants'
6-
import { fetchProjectById, fetchBillingAccount } from '../services/projects'
7+
import { fetchProjectById, fetchBillingAccount, fetchProjectPhases } from '../services/projects'
78

89
/**
910
* Loads project details
@@ -27,6 +28,12 @@ export function loadProject (projectId) {
2728
payload: fetchBillingAccount(projectId)
2829
})
2930

31+
// Loads project phases
32+
dispatch({
33+
type: LOAD_PROJECT_PHASES,
34+
payload: fetchProjectPhases(projectId)
35+
})
36+
3037
return project
3138
})
3239
})

src/components/Buttons/PrimaryButton/PrimaryButton.module.scss

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@
5757
}
5858
}
5959

60+
&.successDark {
61+
@include roboto-bold;
62+
background-color: $tc-green-50;
63+
&:disabled {
64+
cursor: default;
65+
background-color: $inactive;
66+
}
67+
}
68+
6069
/* this style just visually simulates the disable status of the button */
6170
&.disabled {
6271
cursor: default;

0 commit comments

Comments
 (0)