Skip to content
Open
1 change: 1 addition & 0 deletions .github/workflows/wg-easy-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
tags: [ 'v*' ]
paths:
- 'applications/wg-easy/**'
- '!applications/wg-easy/README.md'
- '.github/workflows/wg-easy-image.yml'
pull_request:
paths:
Expand Down
48 changes: 42 additions & 6 deletions .github/workflows/wg-easy-pr-validation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,27 @@ on:
description: 'Run in test mode'
required: false
default: 'true'
workflow_call:
inputs:
channel-name:
description: 'Channel name override (defaults to branch-derived name)'
type: string
default: ''
customer-name:
description: 'Customer name override (defaults to branch-derived name)'
type: string
default: ''
cleanup-cluster:
description: 'Delete test clusters after completion'
type: boolean
default: false
secrets:
WG_EASY_REPLICATED_API_TOKEN:
required: true
outputs:
test-result:
description: 'Result of the test-deployment job'
value: ${{ jobs.test-deployment.result }}

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
Expand All @@ -36,12 +57,19 @@ jobs:
- name: Set branch and channel variables
id: vars
run: |
# Branch name preserves original case for resource naming (clusters, customers)
BRANCH_NAME="${{ github.head_ref || github.ref_name }}"
# Channel name is normalized to lowercase with hyphens for Replicated channels
CHANNEL_NAME=$(echo "$BRANCH_NAME" | tr '[:upper:]' '[:lower:]' | tr '/' '-')
# Customer name uses normalized branch name for idempotent resource creation
CUSTOMER_NAME="${CHANNEL_NAME}"
# Use input overrides when called via workflow_call (e.g. from the weekly test workflow)
if [ -n "${{ inputs.channel-name }}" ]; then
CHANNEL_NAME="${{ inputs.channel-name }}"
BRANCH_NAME="$CHANNEL_NAME"
CUSTOMER_NAME="${{ inputs.customer-name || inputs.channel-name }}"
else
# Branch name preserves original case for resource naming (clusters, customers)
BRANCH_NAME="${{ github.head_ref || github.ref_name }}"
# Channel name is normalized to lowercase with hyphens for Replicated channels
CHANNEL_NAME=$(echo "$BRANCH_NAME" | tr '[:upper:]' '[:lower:]' | tr '/' '-')
# Customer name uses normalized branch name for idempotent resource creation
CUSTOMER_NAME="${CHANNEL_NAME}"
fi
echo "branch-name=$BRANCH_NAME" >> $GITHUB_OUTPUT
echo "channel-name=$CHANNEL_NAME" >> $GITHUB_OUTPUT
echo "customer-name=$CUSTOMER_NAME" >> $GITHUB_OUTPUT
Expand Down Expand Up @@ -747,6 +775,14 @@ jobs:
echo "Started: $(date -u)"
echo "Status: Complete"

- name: Cleanup test cluster
if: always() && inputs.cleanup-cluster
run: |
K8S_VERSION_NORMALIZED=$(echo "${{ matrix.k8s-version }}" | tr '.' '-')
CLUSTER_NAME="${{ needs.setup.outputs.channel-name }}-$K8S_VERSION_NORMALIZED-${{ matrix.distribution }}-${{ github.run_number }}"
echo "Removing cluster: $CLUSTER_NAME"
replicated cluster rm --name "$CLUSTER_NAME" || echo "Cluster cleanup failed or already removed"

- name: Upload debug logs
if: failure()
uses: actions/upload-artifact@v4
Expand Down
212 changes: 212 additions & 0 deletions .github/workflows/wg-easy-weekly-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
---
name: WG-Easy Weekly Test - Verify Chart Installation

on:
schedule:
# Run every Monday at 9:00 AM UTC (1:00 AM PST / 4:00 AM EST)
- cron: '0 9 * * 1'
workflow_dispatch:
inputs:
notify_on_success:
description: 'Send notification even on success'
required: false
default: 'false'
type: boolean

concurrency:
group: wg-easy-weekly-test
cancel-in-progress: false

jobs:
run-tests:
uses: ./.github/workflows/wg-easy-pr-validation.yaml
with:
channel-name: weekly-test
customer-name: weekly-test-customer
cleanup-cluster: true
secrets:
WG_EASY_REPLICATED_API_TOKEN: ${{ secrets.WG_EASY_REPLICATED_API_TOKEN }}

notify-on-failure:
runs-on: ubuntu-24.04
needs: run-tests
if: failure()
permissions:
issues: write
steps:
- name: Create GitHub Issue on Failure
uses: actions/github-script@v7
with:
script: |
const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
const issueTitle = `[Weekly Test Failure] WG-Easy chart installation failed - ${new Date().toISOString().split('T')[0]}`;
const issueBody = `## Weekly Test Failure Report

The weekly automated test for the WG-Easy Helm chart has failed.

**Workflow Run:** ${runUrl}
**Date:** ${new Date().toISOString()}
**Trigger:** ${context.eventName === 'schedule' ? 'Scheduled weekly test' : 'Manual workflow dispatch'}

### Failed Jobs
Check the workflow run for detailed logs and failure information.

### Next Steps
1. Review the workflow logs at the link above
2. Investigate the root cause of the failure
3. Fix any issues with the chart or dependencies
4. Re-run the workflow to verify the fix

### Related Files
- Chart: \`applications/wg-easy/charts/wg-easy/\`
- Workflow: \`.github/workflows/wg-easy-weekly-test.yaml\`

---
*This issue was automatically created by the weekly test workflow.*`;

// Check if there's already an open issue for today
const issues = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
labels: 'automated-test,wg-easy',
per_page: 10
});

const existingIssue = issues.data.find(issue =>
issue.title.includes('[Weekly Test Failure]') &&
issue.title.includes(new Date().toISOString().split('T')[0])
);

if (existingIssue) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: existingIssue.number,
body: `Another test failure occurred in the same day.\n\n**Latest Run:** ${runUrl}`
});
console.log(`Updated existing issue #${existingIssue.number}`);
} else {
const issue = await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: issueTitle,
body: issueBody,
labels: ['automated-test', 'wg-easy', 'bug']
});
console.log(`Created issue #${issue.data.number}`);
}

notify-on-success:
runs-on: ubuntu-24.04
needs: run-tests
if: success() && (github.event.inputs.notify_on_success == 'true' || github.event_name == 'schedule')
permissions:
issues: write
steps:
- name: Comment on latest open issue if exists
uses: actions/github-script@v7
with:
script: |
const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;

const issues = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
labels: 'automated-test,wg-easy',
sort: 'created',
direction: 'desc',
per_page: 10
});

// Only comment on issues that are weekly test failure reports
const failureIssue = issues.data.find(issue =>
issue.title.includes('[Weekly Test Failure]')
);

if (failureIssue) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: failureIssue.number,
body: `✅ **Weekly test passed!**\n\nThe WG-Easy chart is now installing and working correctly.\n\n**Successful Run:** ${runUrl}\n\nConsider closing this issue if the problem is resolved.`
});
console.log(`Added success comment to issue #${failureIssue.number}`);
} else {
console.log('No open weekly test failure issues found - weekly test passed successfully!');
}

update-readme-status:
runs-on: ubuntu-24.04
needs: run-tests
if: always() && github.event_name == 'schedule'
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}

- name: Update README with test results
run: |
README_PATH="applications/wg-easy/README.md"

if [ "${{ needs.run-tests.outputs.test-result }}" == "success" ]; then
STATUS="✅ Passing"
else
STATUS="❌ Failed"
fi

TEST_DATE=$(date -u +"%Y-%m-%d %H:%M UTC")
RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"

# Write only the inner content (the markers remain in place as anchors)
cat > /tmp/status_inner.md <<EOF

## Test Status

| Component | Status | Last Tested | Kubernetes Version | Details |
|-----------|--------|-------------|--------------------|---------|
| Chart Installation | ${STATUS} | ${TEST_DATE} | v1.33 / v1.34 / v1.35 | [View Run](${RUN_URL}) |

*Status automatically updated by [weekly test workflow](${RUN_URL})*

EOF

# Replace content between the marker comments, keeping the markers as anchors
sed -i.bak '/<!-- TEST_STATUS_START -->/,/<!-- TEST_STATUS_END -->/{
/<!-- TEST_STATUS_START -->/{
r /tmp/status_inner.md
}
/<!-- TEST_STATUS_START -->/!{/<!-- TEST_STATUS_END -->/!d}
}' "$README_PATH"
rm -f "${README_PATH}.bak"

echo "Updated README with test status: ${STATUS}"

- name: Check for changes
id: check_changes
run: |
if git diff --quiet applications/wg-easy/README.md; then
echo "changed=false" >> $GITHUB_OUTPUT
else
echo "changed=true" >> $GITHUB_OUTPUT
fi

- name: Commit and push changes
if: steps.check_changes.outputs.changed == 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

git add applications/wg-easy/README.md
git commit -m "chore(wg-easy): update test status in README [skip ci]

Automated test status update from weekly test workflow.

Status: ${{ needs.run-tests.outputs.test-result }}
Run: ${{ github.run_id }}"

git push
31 changes: 31 additions & 0 deletions applications/wg-easy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ This project demonstrates a **composable multi-chart workflow** for packaging an

The target scenario: multiple teams, multiple product verticals, one Replicated release.

<!-- TEST_STATUS_START -->
## Test Status

| Component | Status | Last Tested | Kubernetes Version | Details |
|-----------|--------|-------------|--------------------|---------|
| Chart Installation | ⏳ Pending | Never | v1.33 / v1.34 / v1.35 | - |

*Status automatically updated by weekly test workflow*
<!-- TEST_STATUS_END -->

## The Problem with Monolithic Releases

In a monolithic Replicated application, all components share a single set of release artifacts:
Expand Down Expand Up @@ -148,6 +158,27 @@ Key components:

> **New to Task or Helmfile?** These tools are convenient wrappers around standard Helm and shell commands -- they are not the point of this example. See the [Tooling Guide](docs/tooling-guide.md) for what each tool does, why it was chosen over Make and plain Helm CLI, and how to translate the workflows to your own tooling.

## Automated Testing

### Weekly Chart Validation

The repository includes an automated weekly test workflow that runs every Monday at 9:00 AM UTC to ensure the chart remains installable and functional:

**Workflow:** `.github/workflows/wg-easy-weekly-test.yaml`

**What it tests:**
- Chart validation and linting
- Chart packaging and release creation
- Deployment to a fresh Kubernetes cluster (latest stable version)
- Application health checks and functionality tests

**Notifications:**
- Creates a GitHub Issue automatically when tests fail
- Comments on existing issues when tests pass again
- Can be triggered manually via workflow_dispatch

This provides continuous validation that the chart is always ready to install, even during periods of low development activity.

## Learn More

- [Composable Multi-Chart Walkthrough](../../patterns/composable-multi-chart-walkthrough/README.md) -- end-to-end guided tour of the data flow from chart structure through release assembly
Expand Down
Loading