Skip to content

Commit 535e08e

Browse files
committed
release: add unit test to validate workflow YAML structure
1 parent 1d7221a commit 535e08e

File tree

4 files changed

+206
-1
lines changed

4 files changed

+206
-1
lines changed

pkg/cmd/release/BUILD.bazel

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,19 @@ go_test(
3939
srcs = [
4040
"git_test.go",
4141
"update_releases_test.go",
42+
"update_workflow_test.go",
4243
],
4344
data = glob([
4445
"templates/**",
4546
"testdata/**",
4647
]),
4748
embed = [":release_lib"],
4849
deps = [
50+
"//pkg/testutils/datapathutils",
4951
"//pkg/testutils/release",
5052
"@com_github_cockroachdb_version//:version",
5153
"@com_github_stretchr_testify//require",
5254
"@in_gopkg_yaml_v2//:yaml_v2",
55+
"@in_gopkg_yaml_v3//:yaml_v3",
5356
],
5457
)
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Copyright 2023 The Cockroach Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
on:
16+
schedule:
17+
- cron: 0 0 * * *
18+
# Allows you to run this workflow manually from the Actions tab
19+
workflow_dispatch:
20+
21+
name: Update pkg/testutils/release/cockroach_releases.yaml
22+
jobs:
23+
update-crdb-releases-yaml:
24+
if: github.repository == 'cockroachdb/cockroach'
25+
environment: ${{ github.ref_name == 'master' && 'master' || null }}
26+
strategy:
27+
matrix:
28+
branch:
29+
- "master"
30+
- "release-23.2"
31+
- "release-24.1"
32+
- "release-24.3"
33+
- "release-25.2"
34+
- "release-25.3"
35+
- "release-25.4"
36+
name: Update pkg/testutils/release/cockroach_releases.yaml on ${{ matrix.branch }}
37+
runs-on: ubuntu-latest
38+
steps:
39+
- uses: actions/checkout@v3
40+
with:
41+
ref: "${{ matrix.branch }}"
42+
- name: Mount bazel cache
43+
uses: actions/cache@v3
44+
with:
45+
path: "~/.cache/bazel"
46+
key: bazel
47+
- name: Check for updates
48+
run: |
49+
bazel build //pkg/cmd/release
50+
$(bazel info bazel-bin)/pkg/cmd/release/release_/release update-releases-file
51+
git diff
52+
- name: Update pkg/testutils/release/cockroach_releases.yaml on ${{ matrix.branch }}
53+
uses: peter-evans/create-pull-request@v5
54+
with:
55+
base: "${{ matrix.branch }}"
56+
branch: "crdb-releases-yaml-update-${{ matrix.branch }}"
57+
push-to-fork: "cockroach-teamcity/cockroach"
58+
title: "${{ matrix.branch }}: Update pkg/testutils/release/cockroach_releases.yaml"
59+
author: "CRL Release bot <[email protected]>"
60+
token: "${{ secrets.GH_TOKEN_PR }}"
61+
reviewers: rail,jlinder,celiala
62+
body: |
63+
Update pkg/testutils/release/cockroach_releases.yaml with recent values.
64+
65+
Epic: None
66+
Release note: None
67+
Release justification: test-only updates
68+
commit-message: |
69+
${{ matrix.branch }}: Update pkg/testutils/release/cockroach_releases.yaml
70+
71+
Update pkg/testutils/release/cockroach_releases.yaml with recent values.
72+
73+
Epic: None
74+
Release note: None
75+
Release justification: test-only updates
76+
delete-branch: true

pkg/cmd/release/update_workflow.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,9 @@ func addBranchToWorkflow(branch string) error {
176176
if err := encoder.Encode(&workflow); err != nil {
177177
return fmt.Errorf("failed to encode YAML: %w", err)
178178
}
179-
encoder.Close()
179+
if err := encoder.Close(); err != nil {
180+
return fmt.Errorf("failed to close YAML encoder: %w", err)
181+
}
180182

181183
// Write back to file
182184
if err := os.WriteFile(workflowFile, []byte(buf.String()), 0644); err != nil {
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// Copyright 2025 The Cockroach Authors.
2+
//
3+
// Use of this software is governed by the CockroachDB Software License
4+
// included in the /LICENSE file.
5+
6+
package main
7+
8+
import (
9+
"os"
10+
"testing"
11+
12+
"github.com/cockroachdb/cockroach/pkg/testutils/datapathutils"
13+
"gopkg.in/yaml.v3"
14+
)
15+
16+
// TestWorkflowFileStructure validates that the update_releases.yaml workflow file
17+
// has the expected structure that update_workflow.go depends on.
18+
//
19+
// IMPORTANT: This test uses a reference copy of the workflow file stored in testdata/.
20+
// If you modify .github/workflows/update_releases.yaml, you MUST:
21+
// 1. Update the expectedPath in findBranchNode() if the structure changed
22+
// 2. Copy the updated workflow file to testdata/update_releases.yaml
23+
// 3. Run this test to verify the code still works
24+
//
25+
// This test will catch structural changes that would break update_workflow.go.
26+
func TestWorkflowFileStructure(t *testing.T) {
27+
// Read the reference workflow file from testdata
28+
workflowPath := datapathutils.TestDataPath(t, "update_releases.yaml")
29+
data, err := os.ReadFile(workflowPath)
30+
if err != nil {
31+
t.Fatalf("Failed to read workflow file %s: %v\n"+
32+
"If .github/workflows/update_releases.yaml was renamed or moved, "+
33+
"update testdata/update_releases.yaml", workflowPath, err)
34+
}
35+
36+
var workflow yaml.Node
37+
if err := yaml.Unmarshal(data, &workflow); err != nil {
38+
t.Fatalf("Failed to parse workflow YAML: %v", err)
39+
}
40+
41+
// Validate the structure matches what findBranchNode() expects
42+
branchNode, err := findBranchNode(&workflow)
43+
if err != nil {
44+
t.Fatalf("Workflow file structure validation failed.\n"+
45+
"This likely means the structure of %s has changed.\n"+
46+
"Error: %v\n\n"+
47+
"To fix this:\n"+
48+
"1. Update the expectedPath in findBranchNode() to match the new structure\n"+
49+
"2. Update this test if needed",
50+
workflowFile, err)
51+
}
52+
53+
// Verify it's a sequence node with at least one branch
54+
if branchNode.Kind != yaml.SequenceNode {
55+
t.Fatalf("Expected 'branch' to be a sequence, got %v", branchNode.Kind)
56+
}
57+
58+
if len(branchNode.Content) == 0 {
59+
t.Fatal("Expected at least one branch in the workflow matrix, found none")
60+
}
61+
62+
// Verify branches are strings
63+
for i, node := range branchNode.Content {
64+
if node.Kind != yaml.ScalarNode {
65+
t.Errorf("Branch at index %d is not a scalar node (expected string)", i)
66+
}
67+
}
68+
69+
t.Logf("✓ Workflow structure validation passed")
70+
t.Logf(" Found %d branches in the matrix", len(branchNode.Content))
71+
}
72+
73+
// TestAddBranchToWorkflow_NoOp tests that the branch extraction logic works correctly.
74+
func TestAddBranchToWorkflow_NoOp(t *testing.T) {
75+
// Read the reference workflow file from testdata
76+
workflowPath := datapathutils.TestDataPath(t, "update_releases.yaml")
77+
originalData, err := os.ReadFile(workflowPath)
78+
if err != nil {
79+
t.Fatalf("Failed to read workflow file: %v", err)
80+
}
81+
82+
var workflow yaml.Node
83+
if err := yaml.Unmarshal(originalData, &workflow); err != nil {
84+
t.Fatalf("Failed to parse workflow YAML: %v", err)
85+
}
86+
87+
// Get the branch node
88+
branchNode, err := findBranchNode(&workflow)
89+
if err != nil {
90+
t.Fatalf("Failed to find branch node: %v", err)
91+
}
92+
93+
// Should have at least one branch
94+
if len(branchNode.Content) == 0 {
95+
t.Fatal("No branches found in workflow file")
96+
}
97+
98+
// Get the first branch (should be "master" based on current structure)
99+
firstBranch := branchNode.Content[0].Value
100+
101+
// Verify extracting branches works
102+
var branches []string
103+
for _, item := range branchNode.Content {
104+
if item.Kind == yaml.ScalarNode {
105+
branches = append(branches, item.Value)
106+
}
107+
}
108+
109+
// Verify the first branch is in the list
110+
found := false
111+
for _, b := range branches {
112+
if b == firstBranch {
113+
found = true
114+
break
115+
}
116+
}
117+
118+
if !found {
119+
t.Fatalf("Expected to find branch %q in the workflow file", firstBranch)
120+
}
121+
122+
t.Logf("✓ Successfully extracted %d branches from workflow file", len(branches))
123+
t.Logf(" First branch: %s", firstBranch)
124+
}

0 commit comments

Comments
 (0)