-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add a policy
job_timeout_minutes_is_required
(#488)
* feat: add a policy `job_timeout_minutes_is_required` - #485 * docs: add a policy
- Loading branch information
1 parent
a35f088
commit 0097b0d
Showing
8 changed files
with
197 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# job_timeout_minutes_is_required | ||
|
||
All jobs should set [timeout-minutes](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idtimeout-minutes). | ||
|
||
## Examples | ||
|
||
:x: | ||
|
||
```yaml | ||
jobs: | ||
foo: # The job doesn't have `timeout-minutes` | ||
runs-on: ubuntu-latest | ||
steps: | ||
- run: echo hello | ||
``` | ||
:o: | ||
```yaml | ||
jobs: | ||
foo: | ||
runs-on: ubuntu-latest | ||
timeout-minutes: 30 | ||
steps: | ||
- run: echo hello | ||
``` | ||
## Why? | ||
https://exercism.org/docs/building/github/gha-best-practices#h-set-timeouts-for-workflows | ||
> By default, GitHub Actions kills workflows after 6 hours if they have not finished by then. Many workflows don't need nearly as much time to finish, but sometimes unexpected errors occur or a job hangs until the workflow run is killed 6 hours after starting it. Therefore it's recommended to specify a shorter timeout. | ||
> | ||
> The ideal timeout depends on the individual workflow but 30 minutes is typically more than enough for the workflows used in Exercism repos. | ||
> | ||
> This has the following advantages: | ||
> | ||
> PRs won't be pending CI for half the day, issues can be caught early or workflow runs can be restarted. | ||
> The number of overall parallel builds is limited, hanging jobs will not cause issues for other PRs if they are cancelled early. | ||
## Exceptions | ||
1. All steps set `timeout-minutes` | ||
|
||
```yaml | ||
jobs: | ||
foo: # The job is missing `timeout-minutes`, but it's okay because all steps set timeout-minutes | ||
runs-on: ubuntu-latest | ||
steps: | ||
- run: echo hello | ||
timeout-minutes: 5 | ||
- run: echo bar | ||
timeout-minutes: 5 | ||
``` | ||
2. A job uses a reusable workflow | ||
When a reusable workflow is called with `uses`, `timeout-minutes` is not available. | ||
|
||
```yaml | ||
jobs: | ||
foo: | ||
uses: suzuki-shunsuke/renovate-config-validator-workflow/.github/workflows/validate.yaml@v0.2.3 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package policy | ||
|
||
import ( | ||
"errors" | ||
|
||
"github.com/sirupsen/logrus" | ||
"github.com/suzuki-shunsuke/ghalint/pkg/config" | ||
"github.com/suzuki-shunsuke/ghalint/pkg/workflow" | ||
) | ||
|
||
type JobTimeoutMinutesIsRequiredPolicy struct{} | ||
|
||
func (p *JobTimeoutMinutesIsRequiredPolicy) Name() string { | ||
return "job_timeout_minutes_is_required" | ||
} | ||
|
||
func (p *JobTimeoutMinutesIsRequiredPolicy) ID() string { | ||
return "012" | ||
} | ||
|
||
func (p *JobTimeoutMinutesIsRequiredPolicy) ApplyJob(_ *logrus.Entry, _ *config.Config, _ *JobContext, job *workflow.Job) error { | ||
if job.TimeoutMinutes != 0 { | ||
return nil | ||
} | ||
if job.Uses != "" { | ||
// when a reusable workflow is called with "uses", "timeout-minutes" is not available. | ||
return nil | ||
} | ||
for _, step := range job.Steps { | ||
if step.TimeoutMinutes == 0 { | ||
return errors.New("job's timeout-minutes is required") | ||
} | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package policy_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/sirupsen/logrus" | ||
"github.com/suzuki-shunsuke/ghalint/pkg/policy" | ||
"github.com/suzuki-shunsuke/ghalint/pkg/workflow" | ||
) | ||
|
||
func TestJobTimeoutMinutesIsRequiredPolicy_ApplyJob(t *testing.T) { //nolint:funlen | ||
t.Parallel() | ||
data := []struct { | ||
name string | ||
job *workflow.Job | ||
isErr bool | ||
}{ | ||
{ | ||
name: "normal", | ||
job: &workflow.Job{ | ||
TimeoutMinutes: 30, | ||
Steps: []*workflow.Step{ | ||
{ | ||
Run: "echo hello", | ||
}, | ||
}, | ||
}, | ||
}, | ||
{ | ||
name: "workflow using reusable workflow", | ||
job: &workflow.Job{ | ||
Uses: "suzuki-shunsuke/renovate-config-validator-workflow/.github/workflows/validate.yaml@v0.2.3", | ||
}, | ||
}, | ||
{ | ||
name: "job should have timeout-minutes", | ||
job: &workflow.Job{ | ||
Steps: []*workflow.Step{ | ||
{ | ||
Run: "echo hello", | ||
}, | ||
}, | ||
}, | ||
isErr: true, | ||
}, | ||
{ | ||
name: "all steps have timeout-minutes", | ||
job: &workflow.Job{ | ||
Steps: []*workflow.Step{ | ||
{ | ||
Run: "echo hello", | ||
TimeoutMinutes: 60, | ||
}, | ||
{ | ||
Run: "echo hello", | ||
TimeoutMinutes: 60, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
p := &policy.JobTimeoutMinutesIsRequiredPolicy{} | ||
logE := logrus.NewEntry(logrus.New()) | ||
for _, d := range data { | ||
t.Run(d.name, func(t *testing.T) { | ||
t.Parallel() | ||
if err := p.ApplyJob(logE, nil, nil, d.job); err != nil { | ||
if !d.isErr { | ||
t.Fatal(err) | ||
} | ||
return | ||
} | ||
if d.isErr { | ||
t.Fatal("error must be returned") | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters