diff --git a/.github/workflows/wg-easy-image.yml b/.github/workflows/wg-easy-image.yml index a3c41da6..a1d1a8c7 100644 --- a/.github/workflows/wg-easy-image.yml +++ b/.github/workflows/wg-easy-image.yml @@ -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: diff --git a/.github/workflows/wg-easy-pr-validation.yaml b/.github/workflows/wg-easy-pr-validation.yaml index f01cf04f..45c2c1a6 100644 --- a/.github/workflows/wg-easy-pr-validation.yaml +++ b/.github/workflows/wg-easy-pr-validation.yaml @@ -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 }} @@ -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 @@ -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 diff --git a/.github/workflows/wg-easy-weekly-test.yaml b/.github/workflows/wg-easy-weekly-test.yaml new file mode 100644 index 00000000..7ef2163a --- /dev/null +++ b/.github/workflows/wg-easy-weekly-test.yaml @@ -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 </,//{ + //{ + r /tmp/status_inner.md + } + //!{//!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 diff --git a/applications/wg-easy/README.md b/applications/wg-easy/README.md index 83a65a12..f09a0d07 100644 --- a/applications/wg-easy/README.md +++ b/applications/wg-easy/README.md @@ -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 + +| Component | Status | Last Tested | Kubernetes Version | Details | +|-----------|--------|-------------|--------------------|---------| +| Chart Installation | ⏳ Pending | Never | v1.33 / v1.34 / v1.35 | - | + +*Status automatically updated by weekly test workflow* + + ## The Problem with Monolithic Releases In a monolithic Replicated application, all components share a single set of release artifacts: @@ -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