Skip to content

Commit 00f2bfa

Browse files
Labels, Messages, and Badges for GitHub PRs in GitLab Pipelines (#3886)
This PR add some "bronzing" features to the GitLab CI/CD pipelines: - Updates CI labels when launched from GitHub dispatched actions for a given PR (Ready, Building, Pass/Fail) - Error messages with links to error logs to the GitHub PR thread when a case fails when launched as described above - When scheduled Nightlies are ran the corresponding badges in the README.md file are updated to pass or fail Resolves #3818 Resolves #3845 Resolves #1917
1 parent 6f1c278 commit 00f2bfa

13 files changed

+407
-109
lines changed

.github/copilot-instructions.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
## Change Logging
2+
- Each time you generate code, note the changes in changelog.md
3+
- Follow semantic versioning guidelines
4+
- Include date and description of changes
5+
- periodically perform git commits with clear messages when appropriate
6+
- Never change the branch that we start with
7+
8+
## Code Style
9+
- Follow the existing code style in the repository
10+
- Use consistent indentation (2 spaces)
11+
- Follow the BASH style already in code base especially "${variable}" for variables
12+
- Never add extra whitespace at the end or beginning of lines
13+
- Use pycodestyle for Python code
14+
- Use shfmt where appropriate and shellcheck for linting
15+
16+
## Code Quality
17+
- Ensure code is clean, well-commented, and follows best practices
18+
- Use consistent naming conventions
19+
- Avoid unnecessary complexity at all costs and make sure the code is easy to understand by average developers
20+
- Avoid over-engineering solutions
21+
- Use readable code that conveys intent and meaning over comments
22+
- Write unit tests for new features and bug fixes
23+
- Ensure code is modular and reusable
24+
25+
## Documentation
26+
- use numpy style docstrings for python functions and classes

.github/workflows/trigger-gitlab-piplines.yml

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,17 @@ on:
1313
required: true
1414
type: choice
1515
options:
16-
- 'CTests'
1716
- 'PR Cases'
18-
default: 'CTests'
17+
- 'CTests'
18+
default: 'PR Cases'
1919
hera:
2020
description: 'Hera'
2121
type: boolean
22-
default: true
22+
default: false
2323
gaeac6:
2424
description: 'Gaea C6'
2525
type: boolean
26-
default: false
26+
default: true
2727
# Add more machines by directly using their names as input IDs
2828

2929
jobs:
@@ -56,23 +56,30 @@ jobs:
5656
id: setup
5757
run: |
5858
# Set PR number
59-
echo "PR_NUM=${{ github.event.inputs.pr_number }}" >> ${GITHUB_ENV}
60-
59+
PR_NUM="${{ github.event.inputs.pr_number }}"
60+
if [[ "${PR_NUM}" != "0" ]]; then
61+
if ! gh pr view "${PR_NUM}" --repo "${{ vars.GW_REPO_URL }}" >/dev/null 2>&1; then
62+
echo "PR ${PR_NUM} not found"
63+
exit 1
64+
fi
65+
fi
66+
echo "PR_NUM=${PR_NUM}" >> ${GITHUB_ENV}
67+
6168
# Set pipeline type based on selection
6269
case "${{ github.event.inputs.pipeline_type }}" in
63-
"CTests")
64-
PIPELINE_TYPE="ctests"
65-
;;
6670
"PR Cases")
6771
PIPELINE_TYPE="pr_cases"
6872
;;
73+
"CTests")
74+
PIPELINE_TYPE="ctests"
75+
;;
6976
*)
7077
echo "Invalid pipeline type: ${{ github.event.inputs.pipeline_type }}"
7178
exit 1
7279
;;
7380
esac
7481
echo "PIPELINE_TYPE=${PIPELINE_TYPE}" >> ${GITHUB_ENV}
75-
echo "Selected pipeline type: ${PIPELINE_TYPE}"
82+
7683
7784
# ---------------------------------------------------------------
7885
# Machine Selection Logic
@@ -114,9 +121,12 @@ jobs:
114121
echo "MACHINES=${MACHINES}" >> "${GITHUB_ENV}"
115122
116123
- name: Trigger GitLab Pipeline
124+
env:
125+
GH_TOKEN: ${{ secrets.GITHUBTOKEN }}
117126
run: |
118127
# Important note: This token should be a proper GitLab Pipeline Trigger token
119128
# created via Settings > CI/CD > Pipeline triggers in your GitLab project
129+
120130
curl --verbose --request POST \
121131
--form "token=${{ secrets.GITLAB_TRIGGER_TOKEN }}" \
122132
--form "ref=develop" \
@@ -125,5 +135,12 @@ jobs:
125135
--form "variables[RUN_ON_MACHINES]=${{ env.MACHINES }}" \
126136
--form "variables[PIPELINE_TYPE]=${{ env.PIPELINE_TYPE }}" \
127137
${{ vars.GITLAB_TRIGGER_URL }}
128-
env:
129-
GITLAB_TRIGGER_TOKEN: ${{ secrets.GITLAB_TRIGGER_TOKEN }}
138+
139+
# Add labels for each machine in the list
140+
if [[ "${{ env.PR_NUM }}" != "0" ]]; then
141+
# Use GitHub CLI to add labels to the PR
142+
for MACHINE in ${{ env.MACHINES }}; do
143+
echo "Adding CI Ready label for machine: ${MACHINE}"
144+
gh pr edit ${{ env.PR_NUM }} --repo ${{ vars.GW_REPO_URL }} --add-label "CI-${MACHINE^}-Ready"
145+
done
146+
fi

.gitlab-ci.yml

Lines changed: 63 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,16 @@ stages:
2929
- finalize
3030

3131
variables:
32+
CI_DEBUG_TRACE: "false" # Enable debug tracing for CI jobs
33+
CI_DEBUG_SERVICES: "false" # Enable debug services for CI jobs
3234
PIPELINE_TYPE: pr_cases # Default to PR Cases if not overwritten by GitLab Scheduled Pipelines
3335
RUN_ON_MACHINES: all # Default to all machines (overwritten by triggers)
3436
# Set GFS_CI_RUN_TYPE=nightly in the GitLab Scheuled Pipelines
3537
# to run the nightly against the develop branch
3638
GFS_CI_RUN_TYPE: pr_cases # default value (overwritten by GitLab Scheuled Pipelines)
3739
GW_REPO_URL: https://github.com/NOAA-EMC/global-workflow.git
3840
# Using CI_PIPELINE_ID guarantees uniqueness per pipeline (also used for pslot tags)
39-
WORKSPACE_ID: ${GFS_CI_RUN_TYPE}_${CI_COMMIT_SHORT_SHA}_${CI_PIPELINE_ID}
41+
WORKSPACE_ID: ${GFS_CI_RUN_TYPE}_${PR_NUMBER}_${CI_COMMIT_SHORT_SHA}_${CI_PIPELINE_ID}
4042
# Define a base path that will be used for initial cloning
4143
GIT_CLONE_PATH: ${CI_BUILDS_DIR}/${WORKSPACE_ID}/global-workflow
4244
GIT_DEPTH: 10
@@ -53,19 +55,21 @@ include:
5355

5456
.base_config:
5557
variables:
58+
badge_GIST_ID: "66059582886cb5c2485ff64bf24e7f93"
5659
GIT_STRATEGY: none
5760
before_script:
5861
- |
59-
export GW_RUN_PATH="${CI_BUILDS_DIR}/${WORKSPACE_ID}"
60-
export GW_HOMEgfs="${GIT_CLONE_PATH}" # This is set by GitLab for initial clone
61-
export RUNTESTS_DIR="${GW_RUN_PATH}/RUNTESTS"
62-
62+
echo "Starting GitLab CI pipeline for global-workflow project"
6363
PR_NUMBER=${PR_NUMBER:-0}
6464
if [[ "${PIPELINE_TYPE}" == "ctests" ]]; then
6565
GFS_CI_RUN_TYPE="ctests"
66-
WORKSPACE_ID="${GFS_CI_RUN_TYPE}_${CI_COMMIT_SHORT_SHA}_${CI_PIPELINE_ID}"
66+
WORKSPACE_ID="${GFS_CI_RUN_TYPE}_${PR_NUMBER}_${CI_COMMIT_SHORT_SHA}_${CI_PIPELINE_ID}"
6767
fi
6868
69+
export GW_RUN_PATH="${CI_BUILDS_DIR}/${WORKSPACE_ID}"
70+
export GW_HOMEgfs="${GIT_CLONE_PATH}" # This is set by GitLab for initial clone
71+
export RUNTESTS_DIR="${GW_RUN_PATH}/RUNTESTS"
72+
6973
# Create a date-based directory name for successful nightly runs
7074
# on success of nightly pipelines will have the final directory name
7175
# (GFS_CI_RUN_TYPE)_(SHORT_SHA)_(MMDDYY) such as nightly_affeae_061025
@@ -89,35 +93,84 @@ include:
8993
exit 1
9094
fi
9195
96+
# Setup GitHub CLI for use throughout the pipeline
97+
export GH=$(which gh 2>/dev/null || echo "${HOME}/bin/gh")
98+
if [[ ! -x "${GH}" ]]; then
99+
echo "ERROR: GitHub CLI (gh) not found or not executable. Please install it."
100+
exit 1
101+
fi
102+
92103
# Common build template for all modalities
93104
.build_template:
94-
extends: .base_config
105+
extends:
106+
- .base_config
107+
- .failure_cleanup_template
95108
variables:
96109
GIT_STRATEGY: clone
97110
GIT_SUBMODULE_STRATEGY: recursive
98111
GIT_SSL_NO_VERIFY: "true" # Address potential certificate verification issues
99112
stage: build
100113
script:
101114
- |
102-
echo "Setting up build environment for ${machine}"
115+
echo "Setting up build environment for ${machine^}..."
103116
echo "Using build directory ${GW_HOMEgfs}"
104117
git submodule status
105118
# When GFS_CI_RUN_TYPE is set to "nightly", we use the develop branch
106119
# It should be set when configuring the scheculed nightly pipeline
107120
if [[ ${GFS_CI_RUN_TYPE} == "pr_cases" && ${PR_NUMBER} != 0 ]]; then
108-
echo "pipeline is set to checkout PR_NUMBER=${PR_NUMBER} from ${GW_REPO_URL}"
121+
echo "pipeline is set to checkout PR_NUMBER=${PR_NUMBER} from ${GW_REPO_URL} on machine ${machine^}"
122+
${GH} pr edit ${PR_NUMBER} --repo ${GW_REPO_URL} --add-label "CI-${machine^}-Building" --remove-label "CI-${machine^}-Ready"
109123
git remote add github "${GW_REPO_URL}"
110124
git fetch github
111-
gh pr checkout "${PR_NUMBER}"
125+
${GH} pr checkout "${PR_NUMBER}"
112126
fi
113127
114128
dev/ci/scripts/utils/ci_utils.sh build
115129
build_status=$?
116130
117131
if [[ ${build_status} -ne 0 ]]; then
118132
echo "Build failed with exit code ${build_status}"
133+
# Mark the build as failed, but don't update labels here - let after_script handle it
119134
exit 1
135+
elif [[ ${GFS_CI_RUN_TYPE} == "pr_cases" && ${PR_NUMBER} != 0 ]]; then
136+
${GH} pr edit ${PR_NUMBER} --repo ${GW_REPO_URL} --add-label "CI-${machine^}-Running" --remove-label "CI-${machine^}-Building"
120137
fi
121138
122139
sorc/link_workflow.sh
123140
mkdir -p ${RUNTESTS_DIR}
141+
142+
# Reusable template for failure cleanup in after_script
143+
.failure_cleanup_template:
144+
after_script:
145+
- |
146+
echo "After script is running for job ${CI_JOB_NAME} on ${machine} with status ${CI_JOB_STATUS}"
147+
if [[ ${CI_JOB_STATUS} == "failed" ]]; then
148+
Machine="${machine^}"
149+
echo "Job failed, performing cleanup actions for ${Machine}"
150+
151+
# Re-setup GH if needed
152+
export GH=$(which gh 2>/dev/null || echo "${HOME}/bin/gh")
153+
if [ ! -x "${GH}" ]; then
154+
echo "WARNING: GitHub CLI (gh) not found in after_script, trying to continue anyway"
155+
fi
156+
157+
if [[ "${GFS_CI_RUN_TYPE}" == "pr_cases" && "${PR_NUMBER}" != 0 ]]; then
158+
echo "Updating GitHub labels for PR ${PR_NUMBER} failure on ${Machine}"
159+
${GH} pr edit ${PR_NUMBER} --repo ${GW_REPO_URL} \
160+
--add-label "CI-${Machine}-Failed" \
161+
--remove-label "CI-${Machine}-Building" \
162+
--remove-label "CI-${Machine}-Running" || true
163+
164+
elif [[ "${GFS_CI_RUN_TYPE}" == "nightly" && "${CI_PIPELINE_SOURCE}" == "schedule" ]]; then
165+
echo "Updating nightly badge for ${Machine} failure with GIST ID ${badge_GIST_ID}"
166+
badge_img_file="${TMPDIR:-/tmp}/$(uuidgen)/${machine}_pipeline_badge.svg"
167+
mkdir -p "$(dirname "${badge_img_file}")"
168+
curl -sSL "https://img.shields.io/badge/${machine}_nightly-failed-red?style=flat-round&logo=gitlab" -o "${badge_img_file}"
169+
${GH} gist edit "${badge_GIST_ID}" --add "${badge_img_file}" || true
170+
171+
else
172+
echo "No cleanup actions needed for GFS_CI_RUN_TYPE=${GFS_CI_RUN_TYPE}, CI_PIPELINE_SOURCE=${CI_PIPELINE_SOURCE}"
173+
fi
174+
else
175+
echo "Job status: ${CI_JOB_STATUS}, no failure cleanup needed"
176+
fi

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
[![shellnorms](https://github.com/NOAA-EMC/global-workflow/actions/workflows/linters.yaml/badge.svg)](https://github.com/NOAA-EMC/global-workflow/actions/workflows/linters.yaml)
33
[![pynorms](https://github.com/NOAA-EMC/global-workflow/actions/workflows/pynorms.yaml/badge.svg)](https://github.com/NOAA-EMC/global-workflow/actions/workflows/pynorms.yaml)
44

5-
![Custom badge](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/emcbot/e35aa2904a54deae6bbb1fdc2d960c71/raw/hera.json)
65
![Custom badge](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/emcbot/e35aa2904a54deae6bbb1fdc2d960c71/raw/hercules.json)
76
![Custom badge](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/emcbot/e35aa2904a54deae6bbb1fdc2d960c71/raw/wcoss2.json)
87

8+
![Custom badge](https://gist.githubusercontent.com/emcbot/66059582886cb5c2485ff64bf24e7f93/raw/hera_pipeline_badge.svg)
9+
![Custom badge](https://gist.githubusercontent.com/emcbot/66059582886cb5c2485ff64bf24e7f93/raw/gaeac6_pipeline_badge.svg)
10+
911
The Global Workflow supporting the Global Forecast System (GFS), the Global Ensemble Forecasting System (GEFS), and the Seasonal Forecast System (SFS) with the [UFS-weather-model](https://github.com/ufs-community/ufs-weather-model). Data assimilation, currently only available for the GFS, is provides by both the [GSI](https://github.com/NOAA-EMC/GSI)- and [GDASApp (JEDI)](https://github.com/NOAA-EMC/GDASApp)-based Data Assimilation systems.
1012

1113
In progress [documentation](https://global-workflow.readthedocs.io/en/latest/) is available.

dev/ci/Jenkinsfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ pipeline {
216216
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
217217
script {
218218
def pslot = sh(script: "${HOMEgfs_dev}/ci/scripts/utils/ci_utils.sh get_pslot ${CUSTOM_WORKSPACE}/RUNTESTS ${caseName}", returnStdout: true).trim()
219-
def error_file = "${CUSTOM_WORKSPACE}/RUNTESTS/${pslot}_error.logs"
219+
def error_file = "${CUSTOM_WORKSPACE}/RUNTESTS/EXPDIR/${pslot}/${pslot}_error.logs"
220220
sh(script: " rm -f ${error_file}")
221221
try {
222222
sh(script: """

dev/ci/README-CI-Pipeline.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,4 +187,4 @@ PR_NUMBER=1234 # Set via GitHub trigger
187187

188188
### GitLab Integration
189189
- Uses GitLab pipeline trigger tokens
190-
- Environment-protected secrets for cross-platform communication
190+
- Environment-protected secrets for cross-platform communication

0 commit comments

Comments
 (0)