Skip to content

Commit

Permalink
Ⓜ️ Add if condition
Browse files Browse the repository at this point in the history
  • Loading branch information
jsnjack committed Aug 31, 2023
1 parent 48157b5 commit 9590e58
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 4 deletions.
47 changes: 46 additions & 1 deletion src/backend/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ func (b *Build) runTask(task *Task) ItemStatus {
}
}

// Checking condition in when
// Checking condition in `when`
if task.When != "" {
condCmd := exec.Command("bash", "-c", fmt.Sprintf("[[ %s ]]", task.When))
condCmd.Env = taskCmd.Env
Expand Down Expand Up @@ -236,6 +236,51 @@ func (b *Build) runTask(task *Task) ItemStatus {
}
}

// Checking condition in `if`
if task.If != "" {
condCmd := exec.Command("bash", "-c", task.If)
condCmd.Env = taskCmd.Env
condCmd.Dir = taskCmd.Dir
b.ProcessLogEntry("> Checking `if` condition: "+task.If, bw, task.ID, task.startedAt)
expandedCondCmd := os.Expand(task.If, getEnvMapper(condCmd.Env))
if expandedCondCmd != task.If {
b.ProcessLogEntry(
"> Expanded condition: "+os.Expand(task.If, getEnvMapper(condCmd.Env)), bw, task.ID, task.startedAt,
)
}
condErr := condCmd.Start()
if condErr != nil {
b.ProcessLogEntry(
fmt.Sprintf("> Unable to evaluate the condition: %s", condErr.Error()),
bw, task.ID, task.startedAt,
)
return StatusFailed
}
condKilled := false
condTimer := time.AfterFunc(WHEN_EVAL_TIMEOUT*time.Second, func() {
condKilled = true
condCmd.Process.Kill()
})
condErr = condCmd.Wait()
condTimer.Stop()
if condKilled {
b.ProcessLogEntry(
fmt.Sprintf("> Condition timeouted: %s", condErr.Error()),
bw, task.ID, task.startedAt,
)
return StatusFailed
}
if condErr != nil {
b.ProcessLogEntry(
fmt.Sprintf("> Condition is false: %s. Skipping the task", condErr.Error()),
bw, task.ID, task.startedAt,
)
return StatusSkipped
} else {
b.ProcessLogEntry("> Condition is true", bw, task.ID, task.startedAt)
}
}

// Add executed command to logs
b.ProcessLogEntry("> Running command: "+task.Command, bw, task.ID, task.startedAt)
expandedTaskCmd := os.Expand(task.Command, getEnvMapper(taskCmd.Env))
Expand Down
3 changes: 2 additions & 1 deletion src/backend/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,13 @@ func (j *Job) verifyInterval() error {

// Task is a command to execute
// .Kind - Possible values: `KindMain` for main tasks; one of `StatusRunning` (and etc) for tasks that are executed when
// job status has changed
// the job status has changed
type Task struct {
ID int `json:"id"`
Name string `yaml:"name" json:"name"`
Command string `yaml:"run" json:"run"`
When string `yaml:"when" json:"when"`
If string `yaml:"if" json:"if"`
Env map[string]string `yaml:"env" json:"env"`
Status ItemStatus `json:"status"`
Kind string `json:"kind"`
Expand Down
131 changes: 131 additions & 0 deletions src/frontend/cypress/integration/40build_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -540,4 +540,135 @@ tasks:
cy.get("body").should("contain", "People call him big bill");
});
});

it("should skip task when `if` condition has non-zero exit code", function () {
// Create job
const jobName = "myjob" + new Date().getTime();
cy.request({
url: "/api/jobs/create",
method: "POST",
auth: {
user: "",
pass: "admin",
},
body: {
name: jobName,
},
form: true,
});

const jobContent = `
desc: Condition test
tasks:
- name: Print env
run: env
if: test -n ""
`;

cy.request({
url: "/api/job/" + jobName,
method: "POST",
auth: {
user: "",
pass: "admin",
},
body: {
fileContent: jobContent,
},
form: true,
});

// Create build
cy.request({
url: `/api/job/${jobName}/run`,
method: "POST",
auth: {
user: "",
pass: "admin",
},
body: {},
form: true,
});

cy.visit("/");
cy.login();
cy.get("[data-cy=filter]").clear().type(jobName);
cy.get("[data-cy=open-build-button]").should("have.length", 1);
cy.get("[data-cy-build]")
.invoke("attr", "data-cy-build")
.then((val) => {
cy.get("[data-cy=open-build-button]").click();
cy.url().should("include", "/build/" + val);
cy.get("[data-cy=reload]").click();
cy.get("body").should("contain", "skipped");
cy.get("body").should("contain", "Condition is false");
cy.get("body").should("not.contain", "WAKE_BUILD_ID=");
});
});

it("should run task when `if` condition has exit code 0", function () {
// Create job
const jobName = "myjob" + new Date().getTime();
cy.request({
url: "/api/jobs/create",
method: "POST",
auth: {
user: "",
pass: "admin",
},
body: {
name: jobName,
},
form: true,
});

const jobContent = `
desc: Condition test
params:
- NAME: joe
tasks:
- name: Print env
run: env
when: test -n "$NAME"
`;

cy.request({
url: "/api/job/" + jobName,
method: "POST",
auth: {
user: "",
pass: "admin",
},
body: {
fileContent: jobContent,
},
form: true,
});

// Create build
cy.request({
url: `/api/job/${jobName}/run`,
method: "POST",
auth: {
user: "",
pass: "admin",
},
body: {},
form: true,
});

cy.visit("/");
cy.login();
cy.get("[data-cy=filter]").clear().type(jobName);
cy.get("[data-cy=open-build-button]").should("have.length", 1);
cy.get("[data-cy-build]")
.invoke("attr", "data-cy-build")
.then((val) => {
cy.get("[data-cy=open-build-button]").click();
cy.url().should("include", "/build/" + val);
cy.get("[data-cy=reload]").click();
cy.get("body").should("contain", "Condition is true");
cy.get("body").should("contain", "WAKE_BUILD_ID=");
});
});
});
5 changes: 3 additions & 2 deletions src/frontend/src/assets/configDescription.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ tasks:

- name: Cow says
run: fortune | cowsay
# `run` is executed when the condition in `when` evaluates to `true`
# command in `run` is executed when the condition in `when` evaluates to `true`
# The condition uses `[[` syntax from bash (https://devhints.io/bash#conditionals)
when: $USER == joe
# command in `run` is executed when the command in `if` has exit code 0
if: test -f API.md
env:
KEY: secret
HTTPS: true
Expand Down Expand Up @@ -78,7 +80,6 @@ on_pending:
finally:
- name: List all files
run: ls -alh

# Default environmetal variables, inject by wake:
# "WAKE_BUILD_ID" - current build id, e.g. 169
# "WAKE_BUILD_WORKSPACE" - path to the build's workspace, e.g. ~/workspace/169/
Expand Down

0 comments on commit 9590e58

Please sign in to comment.