Skip to content

Commit c7de35b

Browse files
authored
feat: Wait for task to complete instead of entire build (#18)
* feat: Wait for task to complete instead of entire build * feat: Wait for task to complete instead of entire build * feat: Wait for task to complete instead of entire build * tweak messages * remove debug logging
1 parent 36141a7 commit c7de35b

File tree

6 files changed

+164
-21
lines changed

6 files changed

+164
-21
lines changed

.github/workflows/publish-dev.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
on:
2+
push:
3+
tags:
4+
- dev*
5+
jobs:
6+
publish:
7+
runs-on: ubuntu-latest
8+
steps:
9+
- uses: actions/checkout@v3
10+
- name: Set release version
11+
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
12+
- uses: actions/setup-node@v3
13+
with:
14+
node-version: 14
15+
- run: sudo npm install -g tfx-cli
16+
- run: ./scripts/dev.sh
17+
env:
18+
PUBLISHER_TOKEN: ${{ secrets.PUBLISHER_TOKEN }}

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,7 @@ build: clean
1717
.PHONY: package
1818
package: build
1919
tfx extension create --manifest-globs vss-extension.json
20+
21+
.PHONY: package-dev
22+
package-dev: build
23+
tfx extension create --manifest-globs vss-extension.dev.json

scripts/dev.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/usr/bin/env bash
2+
3+
set -e
4+
5+
echo "Base version: ${RELEASE_VERSION}"
6+
SIMPLE_VERSION=$(echo "${RELEASE_VERSION}" | sed 's/dev\(.*\)/\1/')
7+
echo "Simple version: ${SIMPLE_VERSION}"
8+
sed -i s/VERSION_PLACEHOLDER/$SIMPLE_VERSION/ vss-extension.dev.json
9+
SPLIT_VERSION=$(echo $SIMPLE_VERSION | awk -F. {'printf "\"Major\":%d,\"Minor\":%d,\"Patch\":%d", $1, $2, $3'})
10+
echo "Split version: ${SPLIT_VERSION}"
11+
sed -i "s/VERSION_PLACEHOLDER/$SPLIT_VERSION/" tfsec-task/task.json
12+
make package-dev
13+
tfx extension publish --manifest-globs vss-extension.dev.json --token "${PUBLISHER_TOKEN}" --share-with liamgalvin

ui/src/App.tsx

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ import {
99
import * as SDK from "azure-devops-extension-sdk";
1010
import * as API from "azure-devops-extension-api";
1111
import {CommonServiceIds, IProjectInfo, IProjectPageService} from "azure-devops-extension-api";
12-
import {TimelineRecord} from "azure-devops-extension-api/Build/Build";
12+
import {TimelineRecord, TimelineRecordState} from "azure-devops-extension-api/Build/Build";
1313
import {ResultSet} from './tfsec'
1414
import {Loading} from './Loading'
1515
import {ResultsTable} from './ResultsTable'
1616
import {Crash} from './Crash'
1717

1818
type AppState = {
19-
status: BuildStatus
19+
status: TimelineRecordState
2020
error: string
2121
resultSet: ResultSet
2222
sdkReady: boolean
@@ -41,7 +41,7 @@ export class App extends React.Component<AppProps, AppState> {
4141
this.props = props
4242
this.state = {
4343
sdkReady: false,
44-
status: BuildStatus.None,
44+
status: TimelineRecordState.Pending,
4545
error: "",
4646
resultSet: {
4747
results: []
@@ -52,21 +52,28 @@ export class App extends React.Component<AppProps, AppState> {
5252
async check() {
5353

5454
const build = await this.buildClient.getBuild(this.project.id, this.buildPageData.build.id)
55-
if ((build.status & BuildStatus.Completed) === 0) {
56-
this.setState({status: build.status})
55+
// if the build isn't running/finished, try again shortly
56+
if ((build.status & BuildStatus.Completed) === 0 && (build.status & BuildStatus.InProgress) === 0) {
57+
this.setState({status: TimelineRecordState.Pending})
5758
setTimeout(this.check.bind(this), this.props.checkInterval)
5859
return
5960
}
60-
6161
const timeline = await this.buildClient.getBuildTimeline(this.project.id, build.id)
6262
let recordId = ""
63+
let recordState: TimelineRecordState;
6364
timeline.records.forEach(function (record: TimelineRecord) {
6465
if (record.type == "Task" && record.name == "tfsec") {
6566
recordId = record.id
67+
recordState = record.state
6668
}
6769
})
6870
if (recordId === "") {
69-
this.setState({error: "Timeline record missing: cannot load results. Is tfsec configured to run on this build?"})
71+
setTimeout(this.check.bind(this), this.props.checkInterval)
72+
return
73+
}
74+
if (recordState !== TimelineRecordState.Completed) {
75+
this.setState({status: recordState})
76+
setTimeout(this.check.bind(this), this.props.checkInterval)
7077
return
7178
}
7279
const attachments = await this.buildClient.getAttachments(this.project.id, build.id, "JSON_RESULT")
@@ -77,7 +84,7 @@ export class App extends React.Component<AppProps, AppState> {
7784
const attachment = attachments[0];
7885
const data = await this.buildClient.getAttachment(this.project.id, build.id, timeline.id, recordId, "JSON_RESULT", attachment.name)
7986
const resultSet = this.decodeResultSet(data)
80-
this.setState({status: build.status, resultSet: resultSet})
87+
this.setState({status: recordState, resultSet: resultSet})
8188
}
8289

8390
setError(msg: string) {
@@ -116,7 +123,7 @@ export class App extends React.Component<AppProps, AppState> {
116123
// render will know everything!
117124
render() {
118125
return (
119-
this.state.status == BuildStatus.Completed ?
126+
this.state.status == TimelineRecordState.Completed ?
120127
<ResultsTable set={this.state.resultSet}/>
121128
:
122129
(this.state.error !== "" ?

ui/src/Loading.tsx

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import * as React from 'react';
2-
import {BuildStatus} from "azure-devops-extension-api/Build";
32
import {Spinner, SpinnerSize} from "azure-devops-ui/Spinner";
3+
import {TimelineRecordState} from "azure-devops-extension-api/Build/Build";
44

55
interface LoadingProps {
6-
status: BuildStatus
6+
status: TimelineRecordState
77
}
88

99
export class Loading extends React.Component<LoadingProps> {
@@ -17,16 +17,12 @@ export class Loading extends React.Component<LoadingProps> {
1717

1818
getMessage(): string {
1919
switch (this.props.status) {
20-
case BuildStatus.None:
21-
return "Initialising..."
22-
case BuildStatus.Cancelling:
23-
return "Cancelling build..."
24-
case BuildStatus.InProgress:
25-
return "Waiting for build to complete..."
26-
case BuildStatus.NotStarted:
27-
return "Waiting for build to start..."
28-
case BuildStatus.Postponed:
29-
return "Build postponed, waiting..."
20+
case TimelineRecordState.Pending:
21+
return "Loading..."
22+
case TimelineRecordState.InProgress:
23+
return "Waiting for scan to complete..."
24+
case TimelineRecordState.Completed:
25+
return "Scan complete!"
3026
}
3127
return "Loading..."
3228
}

vss-extension.dev.json

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
{
2+
"manifestVersion": 1,
3+
"id": "tfsec-official-dev",
4+
"publisher": "AquaSecurityOfficial",
5+
"version": "VERSION_PLACEHOLDER",
6+
"name": "tfsec-dev",
7+
"description": "tfsec uses static analysis of your terraform code to spot potential misconfigurations and help you to resolve them.",
8+
"repository": {
9+
"type": "git",
10+
"uri": "https://github.com/aquasecurity/tfsec-azure-pipelines-task"
11+
},
12+
"public": false,
13+
"categories": [
14+
"Azure Pipelines"
15+
],
16+
"targets": [
17+
{
18+
"id": "Microsoft.VisualStudio.Services"
19+
}
20+
],
21+
"tags": [
22+
"tfsec",
23+
"terraform",
24+
"security",
25+
"scanner"
26+
],
27+
"icons": {
28+
"default": "images/extension-icon.png"
29+
},
30+
"files": [
31+
{
32+
"path": "tfsec-task"
33+
},
34+
{
35+
"path": "ui/node_modules/vss-web-extension-sdk/lib",
36+
"addressable": true,
37+
"packagePath": "lib"
38+
},
39+
{
40+
"path": "LICENSE",
41+
"addressable": true
42+
},
43+
{
44+
"path": "ui/build/static",
45+
"addressable": true,
46+
"packagePath": "static"
47+
},
48+
{
49+
"path": "ui/build/index.html",
50+
"addressable": true,
51+
"packagePath": "index.html"
52+
},
53+
{
54+
"path": "screenshot.png",
55+
"addressable": true
56+
},
57+
{
58+
"path": "images/tfsec.png",
59+
"addressable": true,
60+
"packagePath": "images/tfsec.png"
61+
}
62+
],
63+
"content": {
64+
"license": {
65+
"path": "LICENSE"
66+
},
67+
"details": {
68+
"path": "marketplace.md"
69+
}
70+
},
71+
"links": {
72+
"home": {
73+
"uri": "https://www.aquasec.com/"
74+
},
75+
"license": {
76+
"uri": "./LICENSE"
77+
}
78+
},
79+
"contributions": [
80+
{
81+
"id": "custom-build-release-task",
82+
"type": "ms.vss-distributed-task.task",
83+
"targets": [
84+
"ms.vss-distributed-task.tasks"
85+
],
86+
"properties": {
87+
"name": "tfsec-task"
88+
}
89+
},
90+
{
91+
"id": "tfsec-tab",
92+
"type": "ms.vss-build-web.build-results-tab",
93+
"description": "Results for tfsec scan",
94+
"targets": ["ms.vss-build-web.build-results-view"],
95+
"properties": {
96+
"name": "tfsec",
97+
"uri": "index.html",
98+
"supportsTasks": ["c4d1b8a0-2ef3-4ed7-86ae-a83946199e82"]
99+
}
100+
}
101+
],
102+
"scopes": [
103+
"vso.build_execute"
104+
]
105+
}

0 commit comments

Comments
 (0)