gitgreen 0.1.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +73 -48
  2. package/dist/init.js +22 -71
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -5,71 +5,96 @@ Self-contained carbon calculation CLI for GitLab jobs (no API server). It reuses
5
5
  ## Install
6
6
  - From npm (global CLI):
7
7
  ```bash
8
- pnpm add -g gitgreen-cli
9
- # or: npm install -g gitgreen-cli
8
+ npm install -g gitgreen
10
9
  gitgreen --help
11
10
  ```
12
11
 
13
- - From this repo:
14
- ```bash
15
- # from repo root
16
- pnpm -C node-module install
17
- # build happens via prepare; dist/ is ready for CI
18
- ```
19
-
20
- Run tests (pnpm preferred):
12
+ Run tests:
21
13
  ```bash
22
- pnpm -C node-module test
23
- # or: npm --prefix node-module test
14
+ npm test
24
15
  ```
25
16
 
26
17
  Stress test multiple live configs (build first, real APIs):
27
18
  ```bash
28
- pnpm -C node-module build
29
- pnpm -C node-module stress
19
+ npm build
20
+ npm stress
30
21
  ```
31
22
 
32
23
  ## Usage
33
- ```bash
34
- gitgreen \
35
- --provider gcp \
36
- --machine e2-standard-4 \
37
- --region us-central1-a \
38
- --duration 1800 \
39
- --cpu 55 \
40
- --budget 500 \
41
- --fail-on-budget \
42
- --out-md carbon-report.md \
43
- --out-json carbon-report.json \
44
- --post-note
45
- ```
46
24
 
47
- ### Interactive GitLab setup
25
+ ### Initializing a New GitLab Project
26
+
27
+ To get started with carbon tracking in any GitLab project (any project with a remote pointing to a GitLab instance), run:
28
+
48
29
  ```bash
49
30
  # In your repo
50
31
  gitgreen init
51
32
  ```
52
- The wizard asks for provider/machine/region, budgets, MR note preference, then offers to append a ready-made job to `.gitlab-ci.yml` and prints the CI/CD variable checklist (ELECTRICITY_MAPS_API_KEY, provider creds, budget flags).
53
-
54
- Key environment variables (loaded automatically via dotenv):
55
- - `ELECTRICITY_MAPS_API_KEY` (required)
56
- - `ELECTRICITY_MAPS_BASE_URL` (optional, defaults to public endpoint)
57
- - `GCP_PROJECT_ID` / `GOOGLE_CLOUD_PROJECT` (for GCP metric pull)
58
- - `AWS_*` credentials (for CloudWatch metric pull)
59
- - `DATA_DIR` (override bundled data)
60
- - `DEFAULT_PROVIDER`, `PUE_FALLBACK`, `GITLAB_BASE_URL`
61
-
62
- GitLab CI auto-detection uses:
63
- - `CI_JOB_TOKEN`, `CI_PROJECT_ID`, `CI_JOB_ID`, `CI_PIPELINE_ID`, `CI_MERGE_REQUEST_IID`, `CI_SERVER_URL`
64
- - `CI_RUNNER_TAGS` (comma/space separated) to infer machine/region and instance IDs
65
-
66
- ## GitLab snippet
67
- Add variables `ELECTRICITY_MAPS_API_KEY`, `CARBON_BUDGET` (optional), `FAIL_ON_BUDGET` (true/false). Then call:
68
- ```bash
69
- ./scripts/carbon/install-cli.sh
70
- ./scripts/carbon/run-analysis.sh
33
+
34
+ The initialization wizard will guide you through the setup process:
35
+ - Configure provider/machine/region settings
36
+ - Set carbon budgets
37
+ - Configure MR note preferences
38
+ - Choose to use an existing runner or spin up a new one with supported providers
39
+
40
+ After initialization, the wizard will:
41
+ - Append a ready-made job to your `.gitlab-ci.yml`
42
+ - Print the CI/CD variable checklist (ELECTRICITY_MAPS_API_KEY, provider credentials, budget flags)
43
+
44
+ ### How It Works
45
+
46
+ Once initialized, all subsequent pipelines will run on the configured runner, and their performance will be automatically measured. The carbon tracking is implemented using GitLab CI/CD components as a final step in your pipeline. The carbon tracking job itself is not computationally expensive, so it adds minimal overhead to your CI/CD workflows.
47
+
48
+ Key environment variables:
49
+ - `ELECTRICITY_MAPS_API_KEY` (required) - Get a free key from https://api-portal.electricitymaps.com
50
+ - `GCP_PROJECT_ID` / `GOOGLE_CLOUD_PROJECT` (required for GCP) - Your GCP project ID
51
+
52
+ The `gitgreen init` wizard will automatically set all necessary GitLab CI/CD variables for you.
53
+
54
+ ## Providers
55
+ - **GCP**: Fully wired — the CLI parser expects GCP Monitoring JSON, the GitLab component polls GCE metrics, and `gitgreen init` provisions or reuses GCP runners.
56
+
57
+ ## Architecture
58
+ Runtime flow:
71
59
  ```
72
- Artifacts `carbon-report.md` and `carbon-report.json` will be produced; `POST_MR_NOTE=true` will post to the MR when `CI_JOB_TOKEN` is available.
60
+ CPU/RAM timeseries (GCP Monitoring JSON or custom collector)
61
+ |
62
+ v
63
+ +------------------+ +----------------------------+
64
+ | CLI (gitgreen) |--->| CarbonCalculator |
65
+ | - parse metrics | | - PowerProfileRepository |<- machine data in data/*.json
66
+ | - CLI/env opts | | - ZoneMapper (region→zone) |<- static + runtime PUE mapping
67
+ +------------------+ | - IntensityProvider |<- Electricity Maps API
68
+ +-------------+------------+
69
+ |
70
+ v
71
+ +-----------------------------+
72
+ | Report formatter |
73
+ | - Markdown/JSON artifacts |
74
+ | - Budget evaluation |
75
+ +-------------+---------------+
76
+ |
77
+ v
78
+ +-----------------------------+
79
+ | GitLab client (optional) |
80
+ | - MR note via CI_JOB_TOKEN |
81
+ +-----------------------------+
82
+ ```
83
+
84
+ GitLab CI path:
85
+ ```
86
+ Pipeline starts → component script fetches CPU/RAM timeseries from GCP Monitoring
87
+ → writes JSON files → runs `gitgreen --provider gcp ...`
88
+ → emits `carbon-report.md` / `carbon-report.json`
89
+ → optional MR note when CI_JOB_TOKEN is present
90
+ ```
91
+
92
+ ## Adding a provider
93
+ 1. Extend `CloudProvider` and the provider guard in `src/index.ts` so the calculator accepts the new key.
94
+ 2. Add machine power data (`<provider>_machine_power_profiles.json`) and, if needed, CPU profiles to `data/`, then update `PowerProfileRepository.loadMachineData` to load it.
95
+ 3. Map regions to Electricity Maps zones and a PUE default in `ZoneMapper` (or via `data/runtime-pue-mappings.json` for runtime overrides).
96
+ 4. Parse that provider's metrics into the `TimeseriesPoint` shape (timestamp + numeric value) alongside RAM size/usage, and update the CLI/init/templates to pull those metrics.
97
+ 5. Wire any CI automation (runner tags, MR note flags) to pass the correct provider, machine type, and region strings.
73
98
 
74
99
  ## Publish
75
100
  - Ensure version bump in `package.json`
package/dist/init.js CHANGED
@@ -80,80 +80,27 @@ const setVariable = async (auth, project, key, value, masked = false) => {
80
80
  return setVariableApi(auth.baseUrl, auth.pat, project, key, value, masked);
81
81
  }
82
82
  };
83
- const generateCiJob = (runnerTag) => {
83
+ const generateCiJob = (opts = {}) => {
84
+ const { runnerTag, carbonBudget, failOnBudget } = opts;
85
+ let inputs = ` gcp_project_id: $GCP_PROJECT_ID
86
+ gcp_instance_id: $GCP_INSTANCE_ID
87
+ gcp_zone: $GCP_ZONE
88
+ machine_type: $MACHINE_TYPE`;
89
+ if (carbonBudget) {
90
+ inputs += `\n carbon_budget_grams: "${carbonBudget}"`;
91
+ }
92
+ if (failOnBudget) {
93
+ inputs += `\n fail_on_budget: true`;
94
+ }
84
95
  const tagsSection = runnerTag ? `\n tags:\n - ${runnerTag}` : '';
85
96
  return `# GitGreen carbon analysis (generated by gitgreen init)
86
- # Fetches real CPU and RAM metrics from GCP Monitoring API
97
+ include:
98
+ - component: gitlab.com/youneslaaroussi/gitgreen/gitgreen-cli-component@0.1.0
99
+ inputs:
100
+ ${inputs}
87
101
 
88
102
  carbon_analysis:
89
- stage: test${tagsSection}
90
- before_script:
91
- - echo "$GCP_SA_KEY_BASE64" | base64 -d > /tmp/gcp-key.json
92
- - gcloud auth activate-service-account --key-file=/tmp/gcp-key.json
93
- - npm install ./gitgreen-cli-0.1.0.tgz
94
- script:
95
- - |
96
- TOKEN=$(gcloud auth print-access-token)
97
- START_TIME=$(date -u -d "$CI_PIPELINE_CREATED_AT" +%Y-%m-%dT%H:%M:%SZ)
98
- END_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ)
99
-
100
- CPU_FILTER="resource.type=\\"gce_instance\\" AND resource.labels.instance_id=\\"$GCP_INSTANCE_ID\\" AND resource.labels.zone=\\"$GCP_ZONE\\" AND metric.type=\\"compute.googleapis.com/instance/cpu/utilization\\""
101
- CPU_ENCODED=$(python3 -c "import urllib.parse; print(urllib.parse.quote('''$CPU_FILTER'''))")
102
-
103
- RAM_USED_FILTER="resource.type=\\"gce_instance\\" AND resource.labels.instance_id=\\"$GCP_INSTANCE_ID\\" AND metric.type=\\"compute.googleapis.com/instance/memory/balloon/ram_used\\""
104
- RAM_USED_ENCODED=$(python3 -c "import urllib.parse; print(urllib.parse.quote('''$RAM_USED_FILTER'''))")
105
-
106
- RAM_SIZE_FILTER="resource.type=\\"gce_instance\\" AND resource.labels.instance_id=\\"$GCP_INSTANCE_ID\\" AND metric.type=\\"compute.googleapis.com/instance/memory/balloon/ram_size\\""
107
- RAM_SIZE_ENCODED=$(python3 -c "import urllib.parse; print(urllib.parse.quote('''$RAM_SIZE_FILTER'''))")
108
-
109
- # Calculate expected data points (GCP reports every 60s)
110
- START_SEC=$(date -d "$START_TIME" +%s)
111
- NOW_SEC=$(date +%s)
112
- DURATION_SEC=$((NOW_SEC - START_SEC))
113
- EXPECTED_POINTS=$((DURATION_SEC / 60))
114
- [ "$EXPECTED_POINTS" -lt 1 ] && EXPECTED_POINTS=1
115
-
116
- echo "Pipeline duration: \${DURATION_SEC}s, expecting ~\$EXPECTED_POINTS data points"
117
- echo "Waiting for metrics data (GCP has ~3 min lag)..."
118
-
119
- for i in $(seq 1 30); do
120
- END_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ)
121
- CPU_DATA=$(curl -s -H "Authorization: Bearer $TOKEN" \\
122
- "https://monitoring.googleapis.com/v3/projects/$GCP_PROJECT_ID/timeSeries?filter=$CPU_ENCODED&interval.startTime=$START_TIME&interval.endTime=$END_TIME")
123
-
124
- POINTS=$(echo "$CPU_DATA" | python3 -c "import sys,json; d=json.load(sys.stdin); print(sum(len(ts.get('points',[])) for ts in d.get('timeSeries',[])))" 2>/dev/null || echo "0")
125
-
126
- if [ "$POINTS" -ge "$EXPECTED_POINTS" ]; then
127
- echo "Got $POINTS CPU data points (expected $EXPECTED_POINTS)"
128
- break
129
- fi
130
- echo "Waiting for data... got $POINTS/$EXPECTED_POINTS (attempt $i/30)"
131
- sleep 10
132
- done
133
-
134
- # Fetch RAM data
135
- RAM_USED_DATA=$(curl -s -H "Authorization: Bearer $TOKEN" \\
136
- "https://monitoring.googleapis.com/v3/projects/$GCP_PROJECT_ID/timeSeries?filter=$RAM_USED_ENCODED&interval.startTime=$START_TIME&interval.endTime=$END_TIME")
137
-
138
- RAM_SIZE_DATA=$(curl -s -H "Authorization: Bearer $TOKEN" \\
139
- "https://monitoring.googleapis.com/v3/projects/$GCP_PROJECT_ID/timeSeries?filter=$RAM_SIZE_ENCODED&interval.startTime=$START_TIME&interval.endTime=$END_TIME")
140
-
141
- # Save timeseries to files
142
- echo "$CPU_DATA" > /tmp/cpu_timeseries.json
143
- echo "$RAM_USED_DATA" > /tmp/ram_used_timeseries.json
144
- echo "$RAM_SIZE_DATA" > /tmp/ram_size_timeseries.json
145
-
146
- CMD="./node_modules/.bin/gitgreen --provider gcp --machine $MACHINE_TYPE --region $GCP_ZONE --cpu-timeseries /tmp/cpu_timeseries.json --ram-used-timeseries /tmp/ram_used_timeseries.json --ram-size-timeseries /tmp/ram_size_timeseries.json --out-md carbon-report.md --out-json carbon-report.json --no-gitlab"
147
- [ -n "\${CARBON_BUDGET_GRAMS:-}" ] && CMD="$CMD --budget $CARBON_BUDGET_GRAMS"
148
- [ "\${FAIL_ON_BUDGET:-}" = "true" ] && CMD="$CMD --fail-on-budget"
149
-
150
- eval "$CMD"
151
- cat carbon-report.md
152
- artifacts:
153
- paths:
154
- - carbon-report.md
155
- - carbon-report.json
156
- expire_in: 30 days
103
+ extends: .gitgreen-carbon-analysis${tagsSection}
157
104
  `;
158
105
  };
159
106
  const runInit = async (opts = {}) => {
@@ -747,7 +694,11 @@ systemctl start gitlab-runner
747
694
  message: 'Add job to .gitlab-ci.yml?',
748
695
  initial: true
749
696
  });
750
- const ciJob = generateCiJob(runnerTag || undefined);
697
+ const ciJob = generateCiJob({
698
+ runnerTag: runnerTag || undefined,
699
+ carbonBudget: carbonBudget || undefined,
700
+ failOnBudget
701
+ });
751
702
  if (addCiJob) {
752
703
  const ciPath = path_1.default.join(process.cwd(), '.gitlab-ci.yml');
753
704
  if (fs_1.default.existsSync(ciPath)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitgreen",
3
- "version": "0.1.0",
3
+ "version": "1.0.0",
4
4
  "description": "GitGreen CLI for carbon reporting in GitLab pipelines (GCP/AWS)",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",