Repository navigation
127 lines (117 loc) · 4.19 KB
/
Copy pathci.yml
File metadata and controls
127 lines (117 loc) · 4.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
name: CI
# Single entry point for pushes and pull requests. The `changes` job maps the
# diff to the checks that can be affected; unrelated jobs are skipped. The
# final `CI` job is the only required build check, so skipped jobs never leave
# a required status pending. Root Markdown, the changelog, the license, scripts
# and repository metadata trigger nothing beyond this gate.
on:
push:
branches: [master]
pull_request:
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
changes:
name: Detect changes
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
rust: ${{ steps.filter.outputs.rust }}
docs: ${{ steps.filter.outputs.docs }}
audit: ${{ steps.filter.outputs.audit }}
codeql: ${{ steps.filter.outputs.codeql }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Map changed paths to checks
id: filter
env:
EVENT: ${{ github.event_name }}
BASE: ${{ github.event.pull_request.base.sha }}
HEAD: ${{ github.event.pull_request.head.sha }}
BEFORE: ${{ github.event.before }}
SHA: ${{ github.sha }}
run: |
set -euo pipefail
all=false
if [ "$EVENT" = pull_request ]; then
files=$(git diff --name-only "$BASE...$HEAD")
elif [ "$EVENT" = push ] && [ -n "$BEFORE" ] \
&& [ "$BEFORE" != 0000000000000000000000000000000000000000 ] \
&& git cat-file -e "$BEFORE^{commit}" 2> /dev/null; then
files=$(git diff --name-only "$BEFORE" "$SHA")
else
all=true
files=''
fi
printf 'Changed files:\n%s\n' "${files:-(full run)}"
# ci.yml decides what runs, so a change to it runs everything. Each
# reusable workflow only triggers its own check (see the patterns
# below), and any workflow triggers CodeQL, which analyzes Actions.
if grep -qE '^\.github/workflows/ci\.yml$' <<< "$files"; then all=true; fi
match() {
if [ "$all" = true ] || grep -qE "$1" <<< "$files"; then echo true; else echo false; fi
}
rust=$(match '(^(src/|tests/|include/|build\.rs$|Cargo\.(toml|lock)$|\.cargo/|rust-toolchain\.toml$)|^\.github/workflows/rust\.yml$)')
workflows=$(match '^\.github/(workflows/|codeql/)')
{
echo "rust=$rust"
echo "docs=$(match '(^(docs/|zensical\.toml$|requirements-docs\.txt$)|^\.github/workflows/docs\.yml$)')"
echo "audit=$(match '(^Cargo\.lock$|^\.github/workflows/audit\.yml$)')"
if [ "$rust" = true ] || [ "$workflows" = true ] || [ "$all" = true ]; then echo codeql=true; else echo codeql=false; fi
} | tee -a "$GITHUB_OUTPUT"
rust:
name: Rust
needs: changes
if: needs.changes.outputs.rust == 'true'
uses: ./.github/workflows/rust.yml
docs:
name: Docs
needs: changes
if: needs.changes.outputs.docs == 'true'
permissions:
contents: read
pages: write
id-token: write
uses: ./.github/workflows/docs.yml
audit:
name: Audit
needs: changes
if: needs.changes.outputs.audit == 'true'
permissions:
contents: read
issues: write
pull-requests: write
checks: write
uses: ./.github/workflows/audit.yml
codeql:
name: CodeQL
needs: changes
if: needs.changes.outputs.codeql == 'true'
permissions:
contents: read
security-events: write
actions: read
uses: ./.github/workflows/codeql.yml
result:
name: CI
needs: [changes, rust, docs, audit, codeql]
if: always()
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Require every selected check to pass
env:
RESULTS: ${{ toJSON(needs.*.result) }}
run: |
echo "$RESULTS"
if jq -e 'any(.[]; . == "failure" or . == "cancelled")' <<< "$RESULTS" > /dev/null; then
echo '::error::A selected check failed or was cancelled.'
exit 1
fi