-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathaction.yml
More file actions
204 lines (198 loc) · 8.06 KB
/
Copy pathaction.yml
File metadata and controls
204 lines (198 loc) · 8.06 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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# Composite GitHub Action: install c3x and (optionally) run an
# estimate + PR comment in one step.
#
# On a pull request the comment shows the cost DELTA versus the base
# branch ("Total: $533/mo -> $1,038/mo +$505") — the Action estimates
# the base branch automatically. On a push (no base) it shows the
# absolute total.
#
# Usage (after the repo is public):
#
# - uses: c3xdev/c3x@v0
# with:
# path: plan.json # or a Terraform directory
# comment: true # post/update the PR comment
# budget: "1000" # gate on the absolute monthly total
#
# Gate on the per-PR increase (independent of budget). budget-delta
# fails the job when this PR raises the monthly total by more than the
# given amount versus the base branch:
#
# - uses: c3xdev/c3x@v0
# with:
# path: .
# budget-delta: "50" # fail if this PR adds > $50/mo
#
# Or install-only (run c3x yourself afterwards):
#
# - uses: c3xdev/c3x@v0
# with:
# install-only: true
# - run: c3x estimate --path .
#
# Branded comments (post as c3x-cloud[bot] instead of github-actions):
# install the c3x-cloud GitHub App on the repo and grant id-token in the
# workflow, then set branded-comments: true:
#
# permissions:
# pull-requests: write
# id-token: write # required to mint the branded token
# steps:
# - uses: c3xdev/c3x@v0
# with:
# path: .
# branded-comments: true
name: c3x
description: >-
Cloud cost estimation for Terraform & CloudFormation. Installs the
c3x CLI, posts the per-PR cost delta as a comment, and enforces
budget / budget-delta gates. No API key required.
branding:
icon: dollar-sign
color: blue
inputs:
version:
description: c3x version to install (e.g. v0.1.0). "latest" resolves the newest release.
default: latest
install-only:
description: Only install the binary; skip the estimate.
default: "false"
path:
description: Terraform directory, plan JSON, or CloudFormation template.
default: "."
comment:
description: Post/update the cost comment on the current PR (needs pull-requests write).
default: "true"
branded-comments:
description: >-
Post the PR comment as the c3x-cloud[bot] instead of github-actions.
Requires the c3x-cloud GitHub App installed on the repo and
'permissions: id-token: write' in the workflow. Falls back to the
default github-actions identity if either is missing.
default: "false"
token-service:
description: C3X Cloud token service URL (advanced; default token.c3x.dev).
default: "https://token.c3x.dev"
budget:
description: Fail when the monthly total exceeds this amount (0 disables).
default: "0"
budget-delta:
description: >-
Fail when this PR *increases* the monthly total by more than this
amount versus the base branch (0 disables). Independent of budget.
default: "0"
format:
description: Output format for the workflow log (text, markdown, json, junit, html, csv, sarif).
default: text
currency:
description: Display currency (USD, EUR, GBP, ...).
default: ""
runs:
using: composite
steps:
- name: Install c3x
shell: bash
run: |
set -euo pipefail
VERSION="${{ inputs.version }}"
if [ "$VERSION" = "latest" ]; then
VERSION=$(curl -fsSL https://api.github.com/repos/c3xdev/c3x/releases/latest | grep -o '"tag_name": *"[^"]*"' | cut -d'"' -f4)
fi
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$(uname -m); case "$ARCH" in x86_64) ARCH=amd64;; aarch64|arm64) ARCH=arm64;; esac
URL="https://github.com/c3xdev/c3x/releases/download/${VERSION}/c3x_${VERSION#v}_${OS}_${ARCH}.tar.gz"
echo "Installing c3x ${VERSION} (${OS}/${ARCH})"
curl -fsSL "$URL" | tar -xz -C /tmp c3x
sudo install /tmp/c3x /usr/local/bin/c3x
c3x --version
- name: Estimate
if: inputs.install-only != 'true'
shell: bash
run: |
set -euo pipefail
ARGS=(estimate --path "${{ inputs.path }}" --format "${{ inputs.format }}")
if [ "${{ inputs.budget }}" != "0" ]; then
ARGS+=(--budget "${{ inputs.budget }}")
fi
if [ -n "${{ inputs.currency }}" ]; then
ARGS+=(--currency "${{ inputs.currency }}")
fi
c3x "${ARGS[@]}"
- name: Base-branch baseline
id: baseline
if: inputs.install-only != 'true' && github.event_name == 'pull_request' && (inputs.comment == 'true' || inputs.budget-delta != '0')
shell: bash
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: |
# Estimate the PR's BASE branch so the comment / gate can report
# the delta this PR introduces ("+$144 vs main") rather than the
# absolute total. Best-effort: any failure leaves the baseline
# output empty and the comment falls back to the absolute estimate.
set -uo pipefail
out=/tmp/c3x-base.json
if git fetch --no-tags --depth=1 origin "$BASE_SHA" >/dev/null 2>&1 \
&& git worktree add --detach /tmp/c3x-base "$BASE_SHA" >/dev/null 2>&1; then
if c3x estimate --path "/tmp/c3x-base/${{ inputs.path }}" --save-baseline "$out" >/dev/null 2>&1; then
echo "baseline=$out" >> "$GITHUB_OUTPUT"
echo "Computed cost baseline from base $BASE_SHA"
else
echo "::notice::base-branch estimate failed; comment will show the absolute total"
fi
git worktree remove --force /tmp/c3x-base >/dev/null 2>&1 || true
else
echo "::notice::could not check out base branch; comment will show the absolute total"
fi
- name: Budget delta gate
if: inputs.install-only != 'true' && inputs.budget-delta != '0' && steps.baseline.outputs.baseline != ''
shell: bash
run: |
set -euo pipefail
c3x diff --path "${{ inputs.path }}" \
--baseline "${{ steps.baseline.outputs.baseline }}" \
--budget-delta "${{ inputs.budget-delta }}"
- name: PR comment
if: inputs.install-only != 'true' && inputs.comment == 'true' && github.event_name == 'pull_request'
shell: bash
env:
GH_DEFAULT_TOKEN: ${{ github.token }}
BRANDED: ${{ inputs.branded-comments }}
TOKEN_SERVICE: ${{ inputs.token-service }}
OIDC_AUDIENCE: c3x-cloud
run: |
set -euo pipefail
TOKEN="$GH_DEFAULT_TOKEN"
if [ "$BRANDED" = "true" ]; then
# Any failure here is non-fatal: fall back to the default
# github-actions identity rather than dropping the comment.
branded=""
err=""
if [ -n "${ACTIONS_ID_TOKEN_REQUEST_URL:-}" ] && [ -n "${ACTIONS_ID_TOKEN_REQUEST_TOKEN:-}" ]; then
oidc=$(curl -fsSL -H "Authorization: Bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" \
"${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=${OIDC_AUDIENCE}" 2>/dev/null | jq -r '.value // empty' || true)
if [ -n "$oidc" ]; then
resp=$(curl -fsS -X POST "$TOKEN_SERVICE" \
-H "Authorization: Bearer ${oidc}" \
-H 'Content-Type: application/json' \
-d "{\"repo\":\"${GITHUB_REPOSITORY}\"}" 2>/dev/null || true)
branded=$(printf '%s' "$resp" | jq -r '.token // empty')
err=$(printf '%s' "$resp" | jq -r '.error // empty')
else
err="could not obtain OIDC token"
fi
else
err="workflow is missing 'permissions: id-token: write'"
fi
if [ -n "$branded" ]; then
TOKEN="$branded"
echo "Posting comment as c3x-cloud[bot]"
else
echo "::warning::branded comment unavailable (${err:-unknown}); posting as github-actions instead"
fi
fi
ARGS=(comment github --path "${{ inputs.path }}")
if [ -n "${{ steps.baseline.outputs.baseline }}" ]; then
# A baseline was computed from the base branch — post the delta.
ARGS+=(--baseline "${{ steps.baseline.outputs.baseline }}")
fi
GITHUB_TOKEN="$TOKEN" c3x "${ARGS[@]}"