-
Notifications
You must be signed in to change notification settings - Fork 128
140 lines (122 loc) · 5.1 KB
/
ci.yml
File metadata and controls
140 lines (122 loc) · 5.1 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
128
129
130
131
132
133
134
135
136
137
138
139
140
name: CI
env:
PYTHON_VERSION: '3.12'
on:
pull_request:
branches: [ main ]
paths-ignore:
- 'docs/**'
- '.gitignore'
- 'LICENSE'
# Tier 1 also runs in merge queue context so the same unit + build checks
# execute against the tentative merge commit that the queue creates. See
# microsoft/apm#770 for the design.
merge_group:
branches: [ main ]
types: [ checks_requested ]
permissions:
contents: read
jobs:
# Linux-only for PR feedback. Full platform matrix (incl. macOS + Windows) runs post-merge in build-release.yml.
# Combines unit tests + binary build into a single job to eliminate runner re-provisioning overhead.
build-and-test:
name: Build & Test (Linux)
runs-on: ubuntu-24.04
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install uv
uses: astral-sh/setup-uv@v6
with:
enable-cache: true
- name: Install dependencies
run: uv sync --extra dev --extra build
- name: Check YAML encoding safety
run: |
# Ensure YAML file I/O goes through yaml_io helpers.
# Catches yaml.dump/safe_dump writing to a file handle outside yaml_io.py.
VIOLATIONS=$(grep -rn --include='*.py' -P \
'yaml\.(safe_)?dump\(.+,\s*[a-zA-Z_]\w*\b' src/apm_cli/ \
| grep -v 'utils/yaml_io.py' \
| grep -v '# yaml-io-exempt' \
|| true)
if [ -n "$VIOLATIONS" ]; then
echo "::error::Direct yaml.dump() to file handle detected. Use yaml_io.dump_yaml() instead:"
echo "$VIOLATIONS"
exit 1
fi
- name: Run tests
run: uv run pytest tests/unit tests/test_console.py -n auto --dist worksteal
- name: Lint - no raw str(relative_to) patterns
run: |
# Fail if any code uses str(x.relative_to(y)) instead of portable_relpath()
if grep -rn --include="*.py" -P 'str\([^)]*\.relative_to\(' src/apm_cli/ | grep -v portable_relpath | grep -v '\.pyc'; then
echo "::error::Found raw str(path.relative_to()) calls. Use portable_relpath() from apm_cli.utils.paths instead."
exit 1
fi
- name: Install UPX
run: |
sudo apt-get update
sudo apt-get install -y upx-ucl
- name: Build binary
run: |
chmod +x scripts/build-binary.sh
uv run ./scripts/build-binary.sh
- name: Upload binary as workflow artifact
uses: actions/upload-artifact@v4
with:
name: apm-linux-x86_64
# Scripts are included to preserve the artifact root at ./ (not ./dist/).
# Without a sibling directory, upload-artifact strips the dist/ prefix,
# breaking download paths in ci-integration.yml which expects dist/$BINARY_NAME/apm.
path: |
./dist/apm-linux-x86_64
./dist/apm-linux-x86_64.sha256
./scripts/test-release-validation.sh
./scripts/github-token-helper.sh
include-hidden-files: true
retention-days: 30
if-no-files-found: error
# Dogfood the two CI gates we ship and document to users:
# - Gate A (consumer-side): `apm audit --ci` -- lockfile / install fidelity.
# - Gate B (producer-side): regeneration drift -- did someone hand-edit
# a regenerated file under .github/ without updating canonical .apm/?
# See microsoft/apm#883 for context. Tier 1 (no secrets needed).
apm-self-check:
name: APM Self-Check
runs-on: ubuntu-24.04
permissions:
contents: read
steps:
- uses: actions/checkout@v4
# Installs the APM CLI (latest stable) and runs `apm install` against
# this repo's apm.yml. Auto-detects target from the existing .github/
# directory and re-integrates local .apm/ content, regenerating
# .github/instructions/, .github/agents/, .github/skills/, etc.
# Adds `apm` to PATH for subsequent steps.
- uses: microsoft/apm-action@v1
# Gate A: lockfile / install fidelity (consumer-side).
# Verifies every file in lockfile.deployed_files exists, ref consistency
# between apm.yml and apm.lock.yaml, no orphan packages, and
# content-integrity (hidden Unicode) on deployed package content.
# Does NOT verify deployed-file content vs lockfile (see #684).
- name: apm audit --ci
run: apm audit --ci
# Gate B: regeneration drift (producer-side).
# The action's `apm install` step re-integrated local .apm/ into
# .github/ via target auto-detection. If anything in the governed
# integration directories changed, someone edited the regenerated
# output without updating the canonical .apm/ source.
- name: Check APM integration drift
run: |
if [ -n "$(git status --porcelain -- .github/ .claude/ .cursor/ .opencode/)" ]; then
echo "::error::APM integration files are out of date."
echo "Run 'apm install' locally (with .github/ present) and commit the result."
git --no-pager diff -- .github/ .claude/ .cursor/ .opencode/
exit 1
fi