Skip to content
This repository was archived by the owner on Jun 26, 2026. It is now read-only.

Commit 2b405ba

Browse files
twoGiantsclaude
andcommitted
ci: add GitHub Actions CI/CD pipeline
Add single workflow (ci.yml) that runs lint, build, and test on pull requests, then builds and publishes a container image to GHCR on master merge. Follows knative/func patterns: top-level permissions, concurrency groups, version pinning. Fix ESLint config by removing redundant rule spreads that re-enabled the base no-unused-vars rule over the TypeScript version. Add Jest globals for test files. Downgrade @console/pluginAPI shared dep to >=4.19.0. Restructure README: move deployment section to the top with OCP 4.19 prerequisite and GHCR registry link. Add separate prerequisites for deployment and development sections. Add hack/next-plan-number.sh for deterministic plan numbering based on remote PR count. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 47a2c5c commit 2b405ba

13 files changed

Lines changed: 529 additions & 55 deletions

File tree

.github/workflows/ci.yml

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
name: CI
2+
3+
permissions:
4+
id-token: write # Required for signing
5+
contents: read
6+
packages: write
7+
attestations: write
8+
pages: write
9+
10+
on:
11+
push:
12+
branches:
13+
- master
14+
pull_request:
15+
branches:
16+
- master
17+
18+
concurrency:
19+
group: ${{ github.workflow }}-${{ github.ref }}
20+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
21+
22+
env:
23+
IMAGE: ghcr.io/twogiants/console-functions-plugin
24+
25+
jobs:
26+
# --------
27+
# CHECKS
28+
# --------
29+
checks:
30+
name: Lint and Test
31+
runs-on: ubuntu-latest
32+
timeout-minutes: 15
33+
steps:
34+
- uses: actions/checkout@v4
35+
36+
- name: Setup Node.js
37+
uses: actions/setup-node@v4
38+
with:
39+
node-version: "22"
40+
cache: yarn
41+
42+
- name: Enable Corepack
43+
run: corepack enable
44+
45+
- name: Install Dependencies
46+
run: yarn install --immutable
47+
48+
- name: Lint
49+
run: yarn lint
50+
51+
- name: Test
52+
run: yarn test
53+
54+
# -----------
55+
# BUILD IMAGE
56+
# -----------
57+
build-image:
58+
name: Build Image
59+
needs: checks
60+
runs-on: ubuntu-latest
61+
timeout-minutes: 30
62+
steps:
63+
- uses: actions/checkout@v4
64+
- uses: docker/setup-qemu-action@v3
65+
- uses: docker/setup-buildx-action@v3
66+
67+
- name: Build Image
68+
uses: docker/build-push-action@v6
69+
env:
70+
SOURCE_DATE_EPOCH: 0
71+
with:
72+
context: .
73+
push: false
74+
# Multi-arch is required for OCP.
75+
platforms: linux/amd64,linux/arm64,linux/ppc64le,linux/s390x
76+
cache-from: type=gha
77+
cache-to: type=gha,mode=max
78+
79+
# -------------
80+
# PUBLISH IMAGE
81+
# -------------
82+
publish:
83+
name: Publish Image
84+
needs: build-image
85+
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
86+
runs-on: ubuntu-latest
87+
timeout-minutes: 30
88+
outputs:
89+
digest: ${{ steps.build-and-push.outputs.digest }}
90+
steps:
91+
- uses: actions/checkout@v4
92+
- uses: docker/setup-qemu-action@v3
93+
- uses: docker/setup-buildx-action@v3
94+
95+
- name: Login to GHCR
96+
uses: docker/login-action@v3
97+
with:
98+
registry: ghcr.io
99+
username: ${{ github.actor }}
100+
password: ${{ secrets.GITHUB_TOKEN }}
101+
102+
- name: Build and Push Image
103+
id: build-and-push
104+
uses: docker/build-push-action@v6
105+
env:
106+
SOURCE_DATE_EPOCH: 0
107+
with:
108+
context: .
109+
push: true
110+
platforms: linux/amd64,linux/arm64,linux/ppc64le,linux/s390x
111+
tags: |
112+
${{ env.IMAGE }}:latest
113+
${{ env.IMAGE }}:sha-${{ github.sha }}
114+
cache-from: type=gha
115+
annotations: |
116+
index:org.opencontainers.image.description=Serverless Functions Console Plugin for OpenShift
117+
index:org.opencontainers.image.source=https://github.com/twoGiants/func-console
118+
index:org.opencontainers.image.vendor=https://github.com/twoGiants/func-console
119+
index:org.opencontainers.image.url=https://github.com/twoGiants/func-console/pkgs/container/console-functions-plugin
120+
121+
# Attestation is required for OCP.
122+
- name: Attest Build Provenance
123+
uses: actions/attest-build-provenance@v3
124+
with:
125+
subject-name: ${{ env.IMAGE }}
126+
subject-digest: ${{ steps.build-and-push.outputs.digest }}
127+
push-to-registry: true
128+
129+
# ------------
130+
# DEPLOY PAGES
131+
# ------------
132+
deploy-pages:
133+
name: Deploy Pages
134+
needs: publish
135+
runs-on: ubuntu-latest
136+
timeout-minutes: 5
137+
environment:
138+
name: github-pages
139+
url: ${{ steps.deployment.outputs.page_url }}
140+
steps:
141+
- uses: actions/checkout@v4
142+
143+
- name: Setup Helm
144+
uses: azure/setup-helm@v4
145+
146+
- name: Generate deployment YAML
147+
run: |
148+
mkdir public
149+
helm template console-functions-plugin charts/openshift-console-plugin \
150+
-n console-functions-plugin \
151+
--set "plugin.image=${{ env.IMAGE }}@${{ needs.publish.outputs.digest }}" \
152+
> public/plugin.yaml
153+
154+
- name: Upload Pages artifact
155+
uses: actions/upload-pages-artifact@v3
156+
with:
157+
path: ./public
158+
159+
- name: Deploy to GitHub Pages
160+
id: deployment
161+
uses: actions/deploy-pages@v5

AGENTS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ This is the project map. Read this first, every session.
77
FaaS PoC UI for OpenShift Console — React + TypeScript + Webpack + PatternFly 6 + OCP Dynamic Plugin SDK.
88
See `docs/design/` for full design specs.
99

10+
## Writing Style
11+
12+
No em dashes (``). Use commas, periods, or parentheses instead.
13+
1014
## Knowledge Base
1115

1216
| File | Purpose |

README.md

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,47 @@ A Functions-as-a-Service PoC UI for the OpenShift Web Console. Developers create
44

55
Built as an [OpenShift Console dynamic plugin](https://github.com/openshift/console/tree/main/frontend/packages/console-dynamic-plugin-sdk) using React, TypeScript, and PatternFly 6.
66

7-
## Prerequisites
7+
## Deployment on cluster
8+
9+
### Prerequisites
10+
11+
- [oc](https://console.redhat.com/openshift/downloads) CLI
12+
- An [OpenShift 4.19 cluster](https://console.redhat.com/openshift/create)
13+
14+
### Quick install
15+
16+
```shell
17+
oc new-project console-functions-plugin
18+
oc apply -f https://twogiants.github.io/func-console/plugin.yaml
19+
```
20+
21+
### Manual install (requires [Helm](https://helm.sh))
22+
23+
```shell
24+
oc new-project console-functions-plugin
25+
helm upgrade -i console-functions-plugin charts/openshift-console-plugin \
26+
-n console-functions-plugin --create-namespace \
27+
--set "plugin.image=ghcr.io/twogiants/console-functions-plugin:latest@sha256:<digest>"
28+
```
29+
30+
To deploy a specific build, use its git commit SHA as the tag:
31+
32+
```shell
33+
--set "plugin.image=ghcr.io/twogiants/console-functions-plugin:sha-<commit>"
34+
```
35+
36+
Available image tags are listed in the [container registry](https://github.com/twoGiants/func-console/pkgs/container/console-functions-plugin). Consult the chart [values](charts/openshift-console-plugin/values.yaml) file for additional parameters.
37+
38+
## Development
39+
40+
### Prerequisites
841

942
- [Node.js](https://nodejs.org/en/) (v18+)
1043
- [Yarn](https://yarnpkg.com) (v4)
1144
- [oc](https://console.redhat.com/openshift/downloads) CLI
1245
- [Docker](https://www.docker.com) or [podman 3.2.0+](https://podman.io)
1346
- An [OpenShift cluster](https://console.redhat.com/openshift/create)
1447

15-
## Development
16-
1748
### Option 1: Local
1849

1950
In one terminal window, run:
@@ -93,28 +124,6 @@ NOTE: If you have a Mac with Apple silicon, you will need to add the flag
93124
`--platform=linux/amd64` when building the image to target the correct platform
94125
to run in-cluster.
95126

96-
## Deployment on cluster
97-
98-
A [Helm](https://helm.sh) chart is available to deploy the plugin to an OpenShift environment.
99-
100-
The following Helm parameters are required:
101-
102-
`plugin.image`: The location of the image containing the plugin that was previously pushed
103-
104-
Additional parameters can be specified if desired. Consult the chart [values](charts/openshift-console-plugin/values.yaml) file for the full set of supported parameters.
105-
106-
### Installing the Helm Chart
107-
108-
Install the chart using the name of the plugin as the Helm release name into a new namespace or an existing namespace as specified by the `plugin.name` parameter and providing the location of the image within the `plugin.image` parameter by using the following command:
109-
110-
```shell
111-
helm upgrade -i my-plugin charts/openshift-console-plugin -n my-namespace --create-namespace --set plugin.image=my-plugin-image-location
112-
```
113-
114-
NOTE: When deploying on OpenShift 4.10, it is recommended to add the parameter `--set plugin.securityContext.enabled=false` which will omit configurations related to Pod Security.
115-
116-
NOTE: When defining i18n namespace, adhere `plugin__<name-of-the-plugin>` format. The name of the plugin should be extracted from the `consolePlugin` declaration within the [package.json](package.json) file.
117-
118127
## i18n
119128

120129
The plugin uses [react-i18next](https://react.i18next.com/) for translations. The i18n namespace must match

docs/WORKFLOW.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ For each comment: read the full text and its diff hunk context, make the fix, th
3131

3232
## Branching
3333

34-
Create a feature branch per plan: `<NNN>-<type>-<short-name>` where `<NNN>` matches the plan number and `<type>` the conventional commit type as per our [Git Commit Guide](references/commit-message-guide.md#conventional-commits). Example: `001-feat-function-list-empty-state`. If we're on a feature branch already do nothing.
34+
Create a feature branch per plan: `<NNN>-<type>-<short-name>` where `<NNN>` is determined by `./hack/next-plan-number.sh` (next PR number on the remote) and `<type>` is the conventional commit type as per our [Git Commit Guide](references/commit-message-guide.md#conventional-commits). The plan file uses the same number. Example: `010-feat-function-list-empty-state`. If we're on a feature branch already do nothing.
3535

3636
## Pull Requests
3737

docs/claude-progress.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,26 @@
11
# Claude Progress Log
22
# Newest entries first. Agents: append your entry at the top after the header.
33

4+
---
5+
## 2026-04-20 | Session: CI/CD pipeline and ESLint fixes
6+
Worked on: GitHub Actions CI/CD pipeline, ESLint config fixes, README restructure
7+
Completed:
8+
- Single CI workflow (ci.yml) with three jobs: checks (lint + test), build-image (multi-arch Docker build, no push), publish (build + push to GHCR, master only)
9+
- Multi-arch builds (amd64, arm64, ppc64le, s390x) via docker/setup-qemu-action + docker/setup-buildx-action, required for OCP
10+
- Build attestation signing via actions/attest-build-provenance, required for OCP
11+
- OCI annotations on image index (description, source, vendor, url), following knative/func patterns
12+
- Docker layer caching via GHA cache (build-image writes, publish reads)
13+
- Follows knative/func patterns: top-level permissions (id-token, contents, packages, attestations), concurrency groups, cancel-in-progress for PRs
14+
- Fixed ESLint config: removed redundant rule spreads in src/** block that re-enabled base no-unused-vars over @typescript-eslint/no-unused-vars (all 194 lint errors were config issues, not code issues)
15+
- Added Jest globals block for test files
16+
- Downgraded @console/pluginAPI shared dep to >=4.19.0
17+
- Restructured README: deployment section moved to top with OCP 4.19 prerequisite, GHCR registry link, separate prerequisites for deployment and development
18+
- Added hack/next-plan-number.sh for deterministic plan/branch numbering based on remote PR count
19+
- Updated WORKFLOW.md branching convention to use the helper script
20+
- 8 suites, 34 tests, all passing, zero lint errors
21+
Left off: PR #10 open. User needs to enable GITHUB_TOKEN write permissions in repo Settings and add branch protection rule for master.
22+
Blockers: None
23+
424
---
525
## 2026-04-17 | Session: FaaS route rename and nav restructure
626
Worked on: Rename routes from /functions to /faas, restructure nav for both perspectives

docs/features.json

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,9 @@
109109
"UserAvatar is clickable only on the Function List Page, clicking reopens PatModal to change the PAT and associated GitHub user",
110110
"On Create and Edit pages, UserAvatar displays the GitHub user but is not clickable (PAT cannot be changed from those pages)",
111111
"When PatModal is dismissed without a PAT, the Function List Page (both empty state and table view) shows a hint text directing the user to click 'Connect to GitHub' in the top-right corner to set a PAT",
112-
"PAT change logic is encapsulated in a useUserAvatar custom hook following layered architecture (Hook imports Service, Component imports Hook)"
112+
"PAT change logic is encapsulated in a useUserAvatar custom hook following layered architecture (Hook imports Service, Component imports Hook)",
113+
"If the GH PAT is not set in the session then the Create button is inactive/disabled. The tooltiop of the button should say that PAT is required.",
114+
"The GH PAT must not be compiled/hardcode into code at compile time."
113115
],
114116
"passes": false
115117
},
@@ -124,5 +126,29 @@
124126
"Deployed functions without a matching repo still appear in the table with available cluster data (name, namespace, status, replicas, url)"
125127
],
126128
"passes": false
129+
},
130+
{
131+
"category": "technical",
132+
"description": "CI/CD: GitHub Actions pipelines for PR checks and master publish to GHCR, plus lint fixes and README deployment instructions",
133+
"steps": [
134+
"PR pipeline (.github/workflows/pr.yml): triggers on pull_request to master, runs yarn install --immutable, yarn lint, yarn test — branch cannot merge without passing checks and an approval",
135+
"Publish pipeline (.github/workflows/publish.yml): triggers on push to master (merged PRs), runs yarn install --immutable, yarn lint, yarn test, then builds multi-arch container image via docker/build-push-action using existing Dockerfile and pushes to ghcr.io/twogiants/console-functions-plugin with :latest and :sha-<commit> tags",
136+
"Both pipelines use actions/setup-node@v4 with node-version 22, corepack enable, and cache: yarn for Yarn install caching (GitHub runners ship Node 20 by default with corepack disabled)",
137+
"Both pipelines authenticate to GHCR using GITHUB_TOKEN secret with packages:write permission (token added to repo's Actions secrets)",
138+
"Add yarn lint script to package.json if missing, run it, and fix all lint errors in the codebase",
139+
"Update README.md deployment section (lines 96-117) — replace generic Helm boilerplate, placeholder commands, and obsolete OCP 4.10 / i18n notes with concrete instructions: oc new-project console-functions-plugin, helm upgrade -i console-functions-plugin charts/openshift-console-plugin -n console-functions-plugin --create-namespace --set plugin.image=ghcr.io/twogiants/console-functions-plugin:latest@sha256:<digest>"
140+
],
141+
"passes": true
142+
},
143+
{
144+
"category": "functional",
145+
"description": "Set GitHub Secret (KUBECONFIG) on created function repos so GH Actions can deploy to the cluster",
146+
"steps": [
147+
"Add createSecret method to SourceControlService interface",
148+
"Encrypt secret value with repo public key using tweetnacl or libsodium.js",
149+
"Wire into create flow: after repo creation and file push, set KUBECONFIG secret on the repo",
150+
"GH Actions workflow can authenticate to the cluster and run func deploy"
151+
],
152+
"passes": false
127153
}
128154
]

0 commit comments

Comments
 (0)