forked from green-coding-solutions/eco-ci-energy-estimation
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathaction.yml
206 lines (184 loc) · 9.56 KB
/
action.yml
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
205
206
name: 'Eco CI Energy Estimation'
description: 'Estimate the energy of Linux Github Actions Runner VMs via ML Model'
inputs:
task:
description: 'Task to be executed (start-measurement, get-measurement, display-results)'
required: true
branch:
description: 'Used to correctly identify this CI run for the Badge. Uses github.ref_name by default'
default: ${{ github.ref_name }}
required: false
label:
description: 'Label for the get-measurement task, to mark what this measurement correlates to in your workflow'
default: null
required: false
send-data:
description: 'Send metrics data to metrics.green-coding.io to create and display badge, and see an overview of the energy of your CI runs. Set to false to send no data.'
default: true
required: false
show-carbon:
description: 'Uses the grid carbon intensity of the run location to estimate the emitted carbon for the measurements.'
default: true
required: false
display-table:
description: 'Show the energy reading results in a table during display-results step'
default: true
required: false
display-graph:
description: 'Show the graph of the energy use over time during display-results step'
default: true
required: false
display-badge:
description: 'Shows the badge for the ci run during display-results step'
default: true
required: false
pr-comment:
description: 'Add a comment to the PR with the results during display-results step'
default: false
api-base:
description: 'Base URL of the Github API to send data to. Default is api.github.com, but can be changed to your hostname if you have Github Enterprise'
default: 'api.github.com'
required: false
company-uuid:
description: 'If you want to add data to the CarbonDB you can set this to your company UUID'
default: ''
required: false
project-uuid:
description: 'If you want to add data to the CarbonDB you can set this to your project UUID'
default: ''
required: false
machine-uuid:
description: 'If you want to add data to the CarbonDB you can set this to your machine UUID.'
default: ''
required: false
outputs:
data-total-json:
description: "Contains the data of the total measurement which is retrieved by the 'display-results' task."
value: ${{ steps.run-total-model.outputs.data-total-json }}
data-lap-json:
description: "Contains the data of the most recent measurement which is retrieved by the 'get-measurement' task."
value: ${{ steps.run-lap-model.outputs.data-lap-json }}
runs:
using: 'composite'
steps:
- id: guard
if: inputs.task != 'start-measurement' && inputs.task != 'get-measurement' && inputs.task != 'display-results'
shell: bash
run: |
echo 'Please call the Eco-CI Energy Estimation with a valid task name: start-measurement, get-measurement, or display-results' >> $GITHUB_STEP_SUMMARY
echo "Eco-CI task was called with ${{inputs.task}} instead" >> $GITHUB_STEP_SUMMARY
fail('Invalid task name specified')
- id: initialize
if: inputs.task == 'start-measurement' && env.ECO_CI_INIT != 'DONE'
name: Setup
shell: bash
run: |
if command -v python3 &>/dev/null; then
echo "Python is already installed."
else
echo "Python is not installed. Installing..."
apt-get update
apt-get install -y python3.12 python3.12-venv || apt-get install -y python3.10 python3.10-venv
echo "Python has been installed."
fi
python_version=$(python3 --version 2>&1)
python_major_version=$(python3 -c 'import sys; print(sys.version_info[0])')
python_minor_version=$(python3 -c 'import sys; print(sys.version_info[1])')
python_cache_path="/tmp/eco-ci/venv/lib/python${python_major_version}.${python_minor_version}/site-packages"
echo "python_cache_path=$python_cache_path" >> $GITHUB_OUTPUT
# call the initialize function of setup.sh
${{github.action_path}}/scripts/setup.sh initialize -g ${{inputs.display-graph}}
# To identify the hash for our cache we cannot use the classic mechansim of
# hashFiles('/tmp/eco-ci/spec-power-model/requirements.txt')
# hashFiles is restricted to ONLY work in the GITHUB_WORKSPACE which is for the calling action
# therefore we need to construct the hash ourselfs beforehand and save it to an output variable
- if: inputs.task == 'start-measurement' && env.ECO_CI_INIT != 'DONE'
name: Hash requirements file
id: hash-requirements
shell: bash
run: echo "myhash=$(md5sum /tmp/eco-ci/spec-power-model/requirements.txt | cut -d ' ' -f1)" >> $GITHUB_OUTPUT;
- if: inputs.task == 'start-measurement' && env.ECO_CI_INIT != 'DONE'
name: Cache pip packages
id: cache-pip
uses: actions/cache@v4
env:
cache-name: cache-pip-packages
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ${{ steps.initialize.outputs.python_cache_path }}
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ steps.hash-requirements.outputs.myhash }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-${{ steps.hash-requirements.outputs.myhash }}
- if: inputs.task == 'start-measurement' && env.ECO_CI_INIT != 'DONE' && steps.cache-pip.outputs.cache-hit == 'true'
name: Inform about cache hit
continue-on-error: true
shell: bash
run: |
echo "Cache hit succeeded! 😀"
- if: inputs.task == 'start-measurement' && env.ECO_CI_INIT != 'DONE' && steps.cache-pip.outputs.cache-hit != 'true'
name: Inform about cache hit
continue-on-error: true
shell: bash
run: |
echo "Cache hit failed! ❌"
- if: inputs.task == 'start-measurement'
name: Starting measurement
shell: bash
# if measurement is started first time the reporter might not have run already
# we prefer this over manual startint / stopping as it is less error prone for users
run: |
${{github.action_path}}/scripts/setup.sh setup_python
if ${{inputs.send-data}}; then
curl_response=$(curl -s -H "Authorization: Bearer ${{github.token}}" ${{ github.api_url }}/repos/${{ github.repository }}/actions/workflows)
workflow_id=$(echo $curl_response | jq '.workflows[] | select(.name == "${{ github.workflow }}") | .id')
${{github.action_path}}/scripts/vars.sh add_var "WORKFLOW_ID" $workflow_id
else
${{github.action_path}}/scripts/vars.sh add_var "WORKFLOW_ID" ${{github.workflow}}
fi
${{github.action_path}}/scripts/setup.sh start_measurement
echo "ECO_CI_INIT=DONE" >> $GITHUB_ENV;
- if: inputs.task == 'get-measurement'
id: run-lap-model
name: Running estimation model
env:
NAME: ${{ github.workflow }}
shell: bash
run: |
${{github.action_path}}/scripts/make_measurement.sh -l "${{inputs.label}}" -r "${{ github.run_id }}" -b "${{inputs.branch}}" -R "${{ github.repository }}" -c ${{ github.sha }} -sd ${{inputs.send-data}} -s "github" -n "$NAME" -cbc "${{inputs.company-uuid}}" -cbp "${{inputs.project-uuid}}" -cbm "${{inputs.machine-uuid}}"
lap_data_file="/tmp/eco-ci/lap-data.json"
echo "data-lap-json=$(cat $lap_data_file)" >> $GITHUB_OUTPUT
- if: inputs.task == 'display-results'
name: get estimation for total energy
id: run-total-model
shell: bash
run: |
${{github.action_path}}/scripts/display_results.sh -dt ${{inputs.display-table}} -dg ${{inputs.display-graph}} -db ${{inputs.display-badge}} -b "${{inputs.branch}}" -r ${{ github.run_id }} -R "${{ github.repository }}" -sd ${{inputs.send-data}} -sc ${{inputs.show-carbon}} -s "github"
cat "/tmp/eco-ci/output.txt" >> $GITHUB_STEP_SUMMARY
total_data_file="/tmp/eco-ci/total-data.json"
echo "data-total-json=$(cat $total_data_file)" >> $GITHUB_OUTPUT
- if: github.event_name == 'pull_request' && inputs.pr-comment == 'true'
name: Minimize Old Comment and Post New Comment
id: pr-comment
shell: bash
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
COMMENTS=$(curl -s -H "Authorization: Bearer ${{github.token}}" "https://${{inputs.api-base}}/repos/${{ github.repository }}/issues/$PR_NUMBER/comments")
echo "$COMMENTS" | jq -c --arg username "github-actions[bot]" '.[] | select(.user.login == $username and (.body | index("Eco-CI") // false))' | while read -r comment; do
COMMENT_ID=$(echo "$comment" | jq -r '.id')
COMMENT_BODY=$(echo "$comment" | jq -r '.body')
INNER_BODY=$(echo "$COMMENT_BODY" | sed 's/<details><summary>Old Energy Estimation<\/summary>//g' | sed 's/<\/details>//g')
## indentation here is important, otherwise newlines are not properly sent/processed
PAYLOAD=$(jq --null-input --arg body "<details><summary>Old Energy Estimation</summary>
$INNER_BODY
</details>" '{"body": $body}')
curl -s -H "Authorization: Bearer ${{github.token}}" -X PATCH -d "$PAYLOAD" "https://${{inputs.api-base}}/repos/${{ github.repository }}/issues/comments/$COMMENT_ID"
echo "Comment $COMMENT_ID collapsed."
done
NEW_COMMENT=$(cat "/tmp/eco-ci/output-pr.txt" | jq -Rs '.')
API_URL="https://${{inputs.api-base}}/repos/${{ github.repository }}/issues/${PR_NUMBER}/comments"
curl -X POST -H "Authorization: Bearer ${{github.token}}" -d @- $API_URL <<EOF
{
"body": $NEW_COMMENT
}
EOF