Skip to content

Commit

Permalink
feat: implement workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
kyubisation committed Apr 26, 2024
1 parent b67bafb commit 18e2cbb
Show file tree
Hide file tree
Showing 18 changed files with 454 additions and 227 deletions.
44 changes: 23 additions & 21 deletions .github/workflows/container-image-cleanup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Container Image Cleanup
on:
workflow_dispatch: {}
schedule:
- cron: '0 5 * * *'
- cron: '0 3 * * *'

permissions:
packages: write
Expand All @@ -12,9 +12,8 @@ jobs:
container-image-cleanup:
runs-on: ubuntu-latest
env:
CLOSED_PR_RETENTION_DAYS: 14
PACKAGE_NAME: storybook-preview
PR_TAG_PREFIX: preview-pr
CLOSED_PR_RETENTION_DAYS: 5
PACKAGE_NAMES: storybook-preview,visual-regression
steps:
- uses: actions/github-script@v7
with:
Expand All @@ -23,31 +22,34 @@ jobs:
const pullRequests = await github.paginate(
github.rest.pulls.list.endpoint.merge({ owner, repo, state: 'all' })
);
const twoWeeksAgo =
const retentionPivot =
new Date(Date.now() - (+process.env.CLOSED_PR_RETENTION_DAYS * 24 * 60 * 60 * 1000));
const olderThanTwoWeeks = (date) => new Date(date) < twoWeeksAgo;
const olderThanTwoWeeks = (date) => new Date(date) < retentionPivot;
const isExpiredPrTag = (version) => {
const prNumber = +version.metadata?.container?.tags
?.find((t) => t.startsWith(process.env.PR_TAG_PREFIX))?.split(process.env.PR_TAG_PREFIX)[1];
?.find((t) => t.match(/(preview-pr|pr)(\d+)/))?.match(/(preview-pr|pr)(\d+)/)[2];
const pr = pullRequests.find((p) => p.number === prNumber);
return !!prNumber && pr?.state === 'closed' && olderThanTwoWeeks(pr.closed_at);
};
const params = {
package_type: 'container',
package_name: `${repo}/${process.env.PACKAGE_NAME}`,
username: owner
};
const { data: versions } = await github.rest.packages.getAllPackageVersionsForPackageOwnedByUser(params);
const packageNames = process.env.PACKAGE_NAME.split(',').map((n) => n.trim());
let packageDeletionFailed = false;
for (const version of versions.filter(isExpiredPrTag)) {
try {
await github.rest.packages.deletePackageVersionForUser({ ...params, package_version_id: version.id });
console.log(`Deleted ${version.name} (${version.metadata.container.tags.join(', ')})`);
} catch(e) {
console.error(`Failed to delete ${version.name} (${version.metadata.container.tags.join(', ')})`);
console.error(e);
packageDeletionFailed = true;
for (const packageName of packageNames) {
const params = {
package_type: 'container',
package_name: `${repo}/${packageNames}`,
username: owner
};
const { data: versions } = await github.rest.packages.getAllPackageVersionsForPackageOwnedByUser(params);
for (const version of versions.filter(isExpiredPrTag)) {
try {
await github.rest.packages.deletePackageVersionForUser({ ...params, package_version_id: version.id });
console.log(`Deleted ${version.name} (${version.metadata.container.tags.join(', ')})`);
} catch(e) {
console.error(`Failed to delete ${version.name} (${version.metadata.container.tags.join(', ')})`);
console.error(e);
packageDeletionFailed = true;
}
}
}
Expand Down
128 changes: 108 additions & 20 deletions .github/workflows/continuous-integration-secure.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ on:
workflows: [Continuous Integration]
types: [completed]

permissions:
deployments: write
packages: write
pull-requests: write
env:
IMAGE_REPO_PREVIEW: ghcr.io/${{ github.repository }}/storybook-preview
IMAGE_REPO_VISUAL_REGRESSION: ghcr.io/${{ github.repository }}/visual-regression
PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0] != null && github.event.workflow_run.pull_requests[0].number || '' }}
VISUAL_REQUIRED: 'pr: visual review required'
VISUAL_APPROVED: 'pr: visual review approved'
DIFF_URL: https://lyne-visual-regression-diff-pr{}.app.sbb.ch

jobs:
preview-image:
Expand All @@ -23,9 +26,10 @@ jobs:
github.event.workflow_run.head_branch == 'main'
)
)
env:
PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0] != null && github.event.workflow_run.pull_requests[0].number || '' }}
IMAGE_REPO: ghcr.io/${{ github.repository }}/storybook-preview
permissions:
deployments: write
packages: write
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
Expand All @@ -42,7 +46,7 @@ jobs:
uses: actions/github-script@v7
with:
script: |
const environment = process.env.PR_NUMBER ? `preview-pr${process.env.PR_NUMBER}` : 'preview-main';
const environment = process.env.PR_NUMBER ? `pr${process.env.PR_NUMBER}` : 'main';
const payload = { owner: context.repo.owner, repo: context.repo.repo, environment };
const { data: deployment } = await github.rest.repos.createDeployment({
...payload,
Expand All @@ -59,30 +63,26 @@ jobs:
return environment;
result-encoding: string

- name: 'Container: Login to GitHub Container Repository'
run: echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io --username ${{ github.actor }} --password-stdin
- name: 'Container: Build image'
run: docker build -t $IMAGE_REPO:${{ steps.tag-name.outputs.result }} .
- name: 'Container: Build and preview image'
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin
docker build --tag $IMAGE_REPO_PREVIEW:${{ steps.tag-name.outputs.result }} .
docker push $IMAGE_REPO_PREVIEW:${{ steps.tag-name.outputs.result }}
env:
DOCKER_BUILDKIT: 1
- name: 'Container: Publish image'
run: docker push $IMAGE_REPO:${{ steps.tag-name.outputs.result }}

- name: "Add 'preview-available' label"
if: env.PR_NUMBER != ''
# This label is used for filtering deployments in ArgoCD
uses: actions-ecosystem/action-add-labels@v1
with:
labels: preview-available
number: ${{ env.PR_NUMBER }}
run: gh issue edit ${{ env.PR_NUMBER }} --repo ${{ github.repository }} --add-label "preview-available"

codecov:
runs-on: ubuntu-latest
if: >
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success'
env:
PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0] != null && github.event.workflow_run.pull_requests[0].number || '' }}
permissions:
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
Expand All @@ -100,3 +100,91 @@ jobs:
override_pr: ${{ env.PR_NUMBER }}
fail_ci_if_error: true
verbose: true

visual-regression:
runs-on: ubuntu-latest
if: >
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success'
permissions:
checks: write
packages: write
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: yarn
- run: yarn install --frozen-lockfile --non-interactive

- uses: actions/download-artifact@v4
with:
name: visual-regression-screenshots
path: dist/screenshots/
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GH_ACTIONS_ARTIFACT_DOWNLOAD }}

- name: Build diff-app
run: yarn build:diff-app

- name: Create check if changed
uses: actions/github-script@v7
id: screenshot-check
with:
script: |
const { readdirSync, readFileSync } = await import('fs');
// If we have no screenshots, we do not need to create a check or containers.
if (!readdirSync('dist/screenshots').length) {
return 'empty';
}
const diffUrl = process.env.DIFF_URL.replace('{}', process.env.PR_NUMBER);
const diffInfo = JSON.parse(readFileSync('dist/diff.json', 'utf8'));
let previousDiffInfo = {};
try {
const response = await fetch(diffUrl + 'diff.json');
if (response.ok) {
previousDiffInfo = await response.json();
}
} catch {}
// If the diff hash is the same as previously, we do not need to update the state or containers.
if (diffInfo.hash === previousDiffInfo.hash) {
return 'no-change';
}
const { data: deployment } = await github.rest.checks.create(({
owner: context.repo.owner,
repo: context.repo.repo,
name: 'Visual Regression Check',
head_sha: context.payload.workflow_run.head_sha,
status: 'in_progress',
details_url: diffUrl,
output: {
title: 'Visual Regression Check',
summary: diffUrl,
text: `Changes: ${diffInfo.changedAmount}\nNew: ${diffInfo.newAmount}`,
}
});
return 'changed';
result-encoding: string

- name: Remove labels when no failed screenshots exist
if: steps.screenshot-check.outputs.result == 'empty'
run: gh issue edit $PR_NUMBER --remove-label "$VISUAL_REQUIRED"

- name: Add label and create container
if: steps.screenshot-check.outputs.result == 'changed'
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin
docker build --tag $IMAGE_REPO_VISUAL_REGRESSION:pr$PR_NUMBER .
docker push $IMAGE_REPO_VISUAL_REGRESSION:pr$PR_NUMBER
gh issue edit $PR_NUMBER --remove-label "$VISUAL_APPROVED"
gh issue edit $PR_NUMBER --add-label "$VISUAL_REQUIRED"
gh issue edit $PR_NUMBER --add-label "visual-regression-diff-available"
env:
DOCKER_BUILDKIT: 1
39 changes: 32 additions & 7 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ concurrency:

permissions: read-all

env:
IMAGE_REPO_VISUAL_REGRESSION: ghcr.io/${{ github.repository }}/visual-regression

jobs:
lint:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -40,11 +43,6 @@ jobs:
test:
runs-on: ubuntu-latest
needs: lint
services:
visual-regression:
image: ghcr.io/${{ github.repository }}/visual-regression:baseline
ports:
- 8080:8050
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
Expand Down Expand Up @@ -160,14 +158,41 @@ jobs:
onlyChanged: true
externals: '**/components/core/styles/**/*.scss'

visual-regression:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
needs: test
services:
visual-regression:
image: ghcr.io/${{ github.repository }}/visual-regression:baseline
ports:
- 8050:8080
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: yarn
- run: yarn install --frozen-lockfile --non-interactive

- name: Install browser dependencies
run: yarn playwright install-deps
- name: Run visual regression baseline generation
run: yarn test:visual-regression
env:
NODE_ENV: production
- name: Store visual regression output
uses: actions/upload-artifact@v4
with:
name: visual-regression-screenshots
path: dist/screenshots-artifact/

visual-regression-baseline:
runs-on: ubuntu-latest
permissions:
packages: write
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs: test
env:
IMAGE_REPO_VISUAL_REGRESSION: ghcr.io/${{ github.repository }}/visual-regression
services:
visual-regression:
image: ghcr.io/${{ github.repository }}/visual-regression:baseline
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ jobs:
- name: Remove files with forbidden extensions
run: node ./scripts/clean-storybook-files.cjs
- name: 'Container: Login to GitHub Container Repository'
run: echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io --username ${{ github.actor }} --password-stdin
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin
- name: 'Container: Build image'
run: docker build --tag $IMAGE_REPO_STORYBOOK:$VERSION --tag $IMAGE_REPO_STORYBOOK:latest .
env:
Expand Down Expand Up @@ -116,7 +116,7 @@ jobs:
- name: Remove files with forbidden extensions
run: node ./scripts/clean-storybook-files.cjs
- name: 'Container: Login to GitHub Container Repository'
run: echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io --username ${{ github.actor }} --password-stdin
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin
- name: 'Container: Build image'
run: docker build --tag $IMAGE_REPO_STORYBOOK:dev .
env:
Expand Down
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
FROM ghcr.io/nginxinc/nginx-unprivileged:stable

LABEL org.opencontainers.image.source=https://github.com/lyne-design-system/lyne-components

# Copy nginx configuration
COPY ./.github/default.conf /etc/nginx/conf.d/default.conf

Expand Down
Loading

0 comments on commit 18e2cbb

Please sign in to comment.