Skip to content

Commit ac74644

Browse files
authored
Merge branch 'master' into master
2 parents 09985b3 + 56bf4a7 commit ac74644

15 files changed

+189
-118
lines changed

.circleci/config.yml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ parameters:
1010
workflows:
1111
build-deploy:
1212
jobs:
13-
- validate
13+
- validate:
14+
filters:
15+
branches:
16+
ignore:
17+
- master
1418
- test:
1519
requires:
1620
- validate
@@ -83,7 +87,7 @@ jobs:
8387
PUBLISH_MESSAGE=`circleci orb publish promote eddiewebb/<<pipeline.parameters.orbname>>@dev:${PR_NUMBER} ${SEMVER_INCREMENT} --token ${CIRCLECI_API_KEY}`
8488
echo $PUBLISH_MESSAGE
8589
ORB_VERSION=$(echo $PUBLISH_MESSAGE | sed -n 's/Orb .* was promoted to `\(.*\)`.*/\1/p')
86-
echo "export PR_MESSAGE=\"BotComment: *Production* version of orb available for use - \`${ORB_VERSION}\`\"" >> $BASH_ENV
90+
echo "export PR_MESSAGE=\"BotComment: *Production* version of orb available for use - \\\`${ORB_VERSION}\\\`\"" >> $BASH_ENV
8791
fi
8892
- pr-comment
8993

@@ -104,7 +108,7 @@ commands:
104108
command: |
105109
curl -L https://github.com/mikefarah/yq/releases/download/2.1.1/yq_linux_amd64 -o yq
106110
chmod a+x yq
107-
mv yq /usr/local/bin/
111+
mv yq /usr/local/bin/
108112
install-circleci:
109113
description: installs the new CIrcleCI CLI with orb support
110114
steps:
@@ -124,7 +128,6 @@ commands:
124128
command: |
125129
circleci config pack src/ > packed.yml
126130
circleci orb validate packed.yml
127-
128131
pr-comment:
129132
description: add nessage to pr this build originated from
130133
steps:
@@ -136,13 +139,12 @@ commands:
136139
exit 0
137140
fi
138141
curl -X POST -u eddiewebb:${GHI_TOKEN} "https://api.github.com/repos/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/issues/${PR_NUMBER}/comments" -d "{\"body\":\"${PR_MESSAGE}\"}"
139-
140142
pr-info:
141143
description: get PR number this change originated from
142144
steps:
143145
- run:
144146
name: Get PR Info
145147
command: |
146-
PR_NUMBER=`git log -1 --pretty=%s | sed -En 's/(Try|Merge) #([0-9]*)/\2/p'`
148+
PR_NUMBER=`git log -1 --pretty=%s | sed -En 's/(Try|Merge) #([0-9]*).*/\2/p'`
147149
echo "PR_NUMBER is ${PR_NUMBER}"
148150
echo "export PR_NUMBER=${PR_NUMBER}" >> $BASH_ENV

_config.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
theme: jekyll-theme-hacker

bors.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
status = [
2-
"ci/circleci: publish"
2+
'build-deploy'
33
]

src/@orb.yml

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
version: 2.1
2-
description: Blocks the current job until no previous occurences of same job are running on this branch.
2+
description: |
3+
Allows jobs or entire workflows to be queued to ensure they run in serial.
4+
This is ideal for deployments or other activities that must not run concurrently.
5+
May optionaly consider branch-level isolation if unique branches should run concurrently.
6+
This orb requires the project to have an API key in order to query build states.
7+
8+
display:
9+
home_url: https://eddiewebb.github.io/circleci-queue/
10+
source_url: https://github.com/eddiewebb/circleci-queue
311

412
examples:
513
queue_workflow:
6-
description: Used typically as first job and will queue until no jobs from a previous workflow are running
14+
description: Used typically as first job and will queue until no previous workflows are running
715
usage:
816
version: 2.1
917
orbs:
@@ -20,7 +28,10 @@ examples:
2028
- queue/block_workflow
2129

2230
single_concurrency_job:
23-
description: Used to ensure that a single job (deploy) is not run concurrently
31+
description: |
32+
Used to ensure that a only single job (deploy) is not run concurrently.
33+
By default will only queue if the same job from previous worfklows is running on the same branch.
34+
This allows safe jobs like build/test to overlap, minimizing overall queue times.
2435
usage:
2536
version: 2.1
2637
orbs:

src/commands/until_front_of_line.yml

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,6 @@ parameters:
33
type: boolean
44
default: true
55
description: "Should we only consider jobs running on the same branch?"
6-
consider-job:
7-
type: boolean
8-
# deprecated, do not use
9-
description: "Deprecated. Please see block-workflow."
10-
default: true
116
block-workflow:
127
type: boolean
138
# this is false at COMMAND level as intention is to only block CURRENT job.
@@ -29,6 +24,10 @@ parameters:
2924
type: string
3025
default: "github"
3126
description: "Override VCS to 'bitbucket' if needed."
27+
confidence:
28+
type: string
29+
default: "1"
30+
description: "Due to scarce API, we need to requery the recent jobs list to ensure we're not just in a pending state for previous jobs. This number indicates the threhold for API returning no previous pending jobs. Default is a single confirmation."
3231
steps:
3332
- run:
3433
name: Queue Until Front of Line
@@ -72,33 +71,61 @@ steps:
7271
fi
7372
}
7473
74+
fetch_active_workflows(){
75+
cp /tmp/jobstatus.json /tmp/augmented_jobstatus.json
76+
for workflow in `jq -r ".[] | .workflows.workflow_id" /tmp/augmented_jobstatus.json | uniq`
77+
do
78+
echo "Checking time of workflow: ${workflow}"
79+
workflow_file=/tmp/workflow-${workflow}.json
80+
if [ ! -z $TESTING_MOCK_WORKFLOW_RESPONSES ] && [ -f $TESTING_MOCK_WORKFLOW_RESPONSES/${workflow}.json ]; then
81+
echo "Using test mock workflow response"
82+
cat $TESTING_MOCK_WORKFLOW_RESPONSES/${workflow}.json > ${workflow_file}
83+
else
84+
curl -f -s "https://circleci.com/api/v2/workflow/${workflow}?circle-token=${CIRCLECI_API_KEY}" > ${workflow_file}
85+
fi
86+
created_at=`jq -r '.created_at' ${workflow_file}`
87+
echo "Workflow was created at: ${created_at}"
88+
cat /tmp/augmented_jobstatus.json | jq --arg created_at "${created_at}" --arg workflow "${workflow}" '(.[] | select(.workflows.workflow_id == $workflow) | .workflows) |= . + {created_at:$created_at}' > /tmp/augmented_jobstatus-${workflow}.json
89+
#DEBUG echo "new augmented_jobstatus:"
90+
#DEBUG cat /tmp/augmented_jobstatus-${workflow}.json
91+
mv /tmp/augmented_jobstatus-${workflow}.json /tmp/augmented_jobstatus.json
92+
done
93+
}
94+
7595
update_comparables(){
7696
fetch_filtered_active_builds
7797
98+
fetch_active_workflows
99+
78100
load_current_workflow_values
79101
80102
# falsey parameters are empty strings, so always compare against 'true'
81-
if [ "<<parameters.consider-job>>" != "true" ] || [ "<<parameters.block-workflow>>" = "true" ] ;then
103+
if [ "<<parameters.block-workflow>>" = "true" ] ;then
82104
echo "Orb parameter block-workflow is true."
83105
echo "This job will block until no previous workflows have *any* jobs running."
84-
oldest_running_build_num=`jq 'sort_by(.committer_date)| .[0].build_num' /tmp/jobstatus.json`
85-
oldest_commit_time=`jq 'sort_by(.committer_date)| .[0].committer_date' /tmp/jobstatus.json`
106+
oldest_running_build_num=`jq 'sort_by(.workflows.created_at)| .[0].build_num' /tmp/augmented_jobstatus.json`
107+
oldest_commit_time=`jq 'sort_by(.workflows.created_at)| .[0].workflows.created_at' /tmp/augmented_jobstatus.json`
86108
else
87109
echo "Orb parameter block-workflow is false."
88110
echo "Only blocking execution if running previous jobs matching this job: ${CIRCLE_JOB}"
89-
oldest_running_build_num=`jq ". | map(select(.build_parameters.CIRCLE_JOB==\"${CIRCLE_JOB}\")) | sort_by(.committer_date)| .[0].build_num" /tmp/jobstatus.json`
90-
oldest_commit_time=`jq ". | map(select(.build_parameters.CIRCLE_JOB==\"${CIRCLE_JOB}\")) | sort_by(.committer_date)| .[0].committer_date" /tmp/jobstatus.json`
111+
oldest_running_build_num=`jq ". | map(select(.build_parameters.CIRCLE_JOB==\"${CIRCLE_JOB}\")) | sort_by(.workflows.created_at)| .[0].build_num" /tmp/augmented_jobstatus.json`
112+
oldest_commit_time=`jq ". | map(select(.build_parameters.CIRCLE_JOB==\"${CIRCLE_JOB}\")) | sort_by(.workflows.created_at)| .[0].workflows.created_at" /tmp/augmented_jobstatus.json`
91113
fi
92114
echo "Oldest job: $oldest_running_build_num"
93115
if [ -z $oldest_commit_time ];then
94116
echo "API Call for existing jobs failed, failing this build. Please check API token"
117+
echo "All running jobs:"
118+
cat /tmp/jobstatus.json || exit 0
119+
echo "All running jobs with created_at:"
120+
cat /tmp/augmented_jobstatus.json || exit 0
121+
echo "All worfklow details."
122+
cat /tmp/workflow-*.json
95123
exit 1
96124
fi
97125
}
98126
99127
load_current_workflow_values(){
100-
my_commit_time=`jq '.[] | select( .build_num == '"${CIRCLE_BUILD_NUM}"').committer_date' /tmp/jobstatus.json`
101-
128+
my_commit_time=`jq '.[] | select( .build_num == '"${CIRCLE_BUILD_NUM}"').workflows.created_at' /tmp/augmented_jobstatus.json`
102129
}
103130
104131
cancel_current_build(){
@@ -138,15 +165,23 @@ steps:
138165
#
139166
# Queue Loop
140167
#
168+
confidence=0
141169
while true; do
142170
update_comparables
143171
echo "This Workflow Timestamp: $my_commit_time"
144172
echo "Oldest Workflow Timestamp: $oldest_commit_time"
145173
if [[ "$oldest_commit_time" > "$my_commit_time" ]] || [[ "$oldest_commit_time" = "$my_commit_time" ]] ; then
146174
# API returns Y-M-D HH:MM (with 24 hour clock) so alphabetical string compare is accurate to timestamp compare as well
147-
# in event of race, everyone wins
148-
echo "Front of the line, WooHoo!, Build continuing"
149-
break
175+
# recent-jobs API does not include pending, so it is posisble we queried in between a workfow transition, and we;re NOT really front of line.
176+
if [ $confidence -lt <<parameters.confidence>> ];then
177+
# To grow confidence, we check again with a delay.
178+
confidence=$((confidence+1))
179+
echo "API shows no previous jobs/workflows, but it is possible a previous workflow has pending jobs not yet visible in API."
180+
echo "Rerunning check ${confidence}/<<parameters.confidence>>"
181+
else
182+
echo "Front of the line, WooHoo!, Build continuing"
183+
break
184+
fi
150185
else
151186
echo "This build (${CIRCLE_BUILD_NUM}) is queued, waiting for build number (${oldest_running_build_num}) to complete."
152187
echo "Total Queue time: ${wait_time} seconds."

src/jobs/block_workflow.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,6 @@ parameters:
33
type: boolean
44
default: true
55
description: "Should we only consider jobs running on the same branch?"
6-
consider-job:
7-
type: boolean
8-
# deprecated, do not use.
9-
default: false
10-
description: "Deprecated. Please see block-workflow."
116
block-workflow:
127
type: boolean
138
# this is true at JOB level as intention is to block workflow
@@ -24,20 +19,25 @@ parameters:
2419
only-on-branch:
2520
type: string
2621
default: "*"
27-
description: "Only queue on specified branch"
22+
description: "Only queue on specified branch. Default is to enforce serialization on all branches."
2823
vcs-type:
2924
type: string
3025
default: "github"
3126
description: "Override VCS to 'bitbucket' if needed."
27+
confidence:
28+
type: string
29+
default: "1"
30+
description: "Due to scarce API, we need to requery the recent jobs list to ensure we're not just in a pending state for previous jobs. This number indicates the threhold for API returning no previous pending jobs. Default is a single confirmation."
3231

3332
docker:
34-
- image: circleci/node:10 #its just really popular, and therefore fast (cached)
33+
- image: cimg/base:stable
34+
resource_class: small
3535
steps:
3636
- until_front_of_line:
3737
consider-branch: <<parameters.consider-branch>>
38-
consider-job: <<parameters.consider-job>>
3938
block-workflow: <<parameters.block-workflow>>
4039
time: <<parameters.time>>
4140
dont-quit: <<parameters.dont-quit>>
4241
only-on-branch: <<parameters.only-on-branch>>
4342
vcs-type: <<parameters.vcs-type>>
43+
confidence: <<parameters.confidence>>

test/api/nopreviousjobs.json renamed to test/api/jobs/nopreviousjobs.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
{
44
"testing-note":"This represents the current build, with a job that should be serial",
55
"build_num" : 2,
6-
76
"committer_date": "2019-01-17T11:17:24-05:00",
87
"branch" : "master",
98
"build_parameters":{

test/api/onepreviousjob-differentname.json renamed to test/api/jobs/onepreviousjob-differentname.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
"workflows" : {
3232
"job_name" : "adifferentjob",
3333
"job_id" : "random-hash-2",
34-
"workflow_id" : "ec6172d3-b286-4d3a-a1da-c4efba0a0c05",
34+
"workflow_id" : "aaa8751e-eb0d-4b09-12bd-06a9bb763771",
3535
"workspace_id" : "a1892dee-6e9e-4f2e-adbc-a5629a97b483",
3636
"upstream_job_ids" : [ ],
3737
"upstream_concurrency_map" : { },

test/api/onepreviousjobsamename.json renamed to test/api/jobs/onepreviousjobsamename.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
"workflows" : {
3232
"job_name" : "singlejob",
3333
"job_id" : "random-hash-2",
34-
"workflow_id" : "ec6172d3-b286-4d3a-a1da-c4efba0a0c05",
34+
"workflow_id" : "aaa8751e-eb0d-4b09-12bd-06a9bb763771",
3535
"workspace_id" : "a1892dee-6e9e-4f2e-adbc-a5629a97b483",
3636
"upstream_job_ids" : [ ],
3737
"upstream_concurrency_map" : { },
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"stopped_at" : null,
3+
"name" : "build-deploy",
4+
"project_slug" : "test/project",
5+
"pipeline_number" : 1,
6+
"status" : "running",
7+
"id" : "aaa8751e-eb0d-4b09-12bd-06a9bb763771",
8+
"created_at" : "2019-01-17T10:17:23-05:00",
9+
"pipeline_id" : "aaa8751e-eb0d-4b09-12bd-06a9bb763775"
10+
}

0 commit comments

Comments
 (0)