Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 161 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
name: CI

permissions:
id-token: write # Required for signing
contents: read
packages: write
attestations: write
pages: write

on:
push:
branches:
- master
pull_request:
branches:
- master

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

env:
IMAGE: ghcr.io/twogiants/console-functions-plugin

jobs:
# --------
# CHECKS
# --------
checks:
name: Lint and Test
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v6

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "22"
cache: yarn

- name: Enable Corepack
run: corepack enable

- name: Install Dependencies
run: yarn install --immutable

- name: Lint
run: yarn lint

- name: Test
run: yarn test

# -----------
# BUILD IMAGE
# -----------
build-image:
name: Build Image
needs: checks
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v6
- uses: docker/setup-qemu-action@v4
- uses: docker/setup-buildx-action@v4

- name: Build Image
uses: docker/build-push-action@v7
env:
SOURCE_DATE_EPOCH: 0
with:
context: .
push: false
# Multi-arch is required for OCP.
platforms: linux/amd64,linux/arm64,linux/ppc64le,linux/s390x
cache-from: type=gha
cache-to: type=gha,mode=max

# -------------
# PUBLISH IMAGE
# -------------
publish:
name: Publish Image
needs: build-image
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
timeout-minutes: 30
outputs:
digest: ${{ steps.build-and-push.outputs.digest }}
steps:
- uses: actions/checkout@v6
- uses: docker/setup-qemu-action@v4
- uses: docker/setup-buildx-action@v4

- name: Login to GHCR
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and Push Image
Comment thread
matejvasek marked this conversation as resolved.
id: build-and-push
uses: docker/build-push-action@v7
env:
SOURCE_DATE_EPOCH: 0
with:
context: .
push: true
platforms: linux/amd64,linux/arm64,linux/ppc64le,linux/s390x
tags: |
${{ env.IMAGE }}:latest
${{ env.IMAGE }}:sha-${{ github.sha }}
cache-from: type=gha
annotations: |
index:org.opencontainers.image.description=Serverless Functions Console Plugin for OpenShift
index:org.opencontainers.image.source=https://github.com/twoGiants/func-console
index:org.opencontainers.image.vendor=https://github.com/twoGiants/func-console
index:org.opencontainers.image.url=https://github.com/twoGiants/func-console/pkgs/container/console-functions-plugin

# Attestation is required for OCP.
- name: Attest Build Provenance
uses: actions/attest-build-provenance@v4
with:
subject-name: ${{ env.IMAGE }}
subject-digest: ${{ steps.build-and-push.outputs.digest }}
push-to-registry: true

# ------------
# DEPLOY PAGES
# ------------
deploy-pages:
name: Deploy Pages
needs: publish
runs-on: ubuntu-latest
timeout-minutes: 5
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- uses: actions/checkout@v6

- name: Setup Helm
uses: azure/setup-helm@v5

- name: Generate deployment YAML
run: |
mkdir public
helm template console-functions-plugin charts/openshift-console-plugin \
-n console-functions-plugin \
--set "plugin.image=${{ env.IMAGE }}@${{ needs.publish.outputs.digest }}" \
> public/plugin.yaml

- name: Upload Pages artifact
uses: actions/upload-pages-artifact@v5
with:
path: ./public

- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v5
4 changes: 4 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ This is the project map. Read this first, every session.
FaaS PoC UI for OpenShift Console — React + TypeScript + Webpack + PatternFly 6 + OCP Dynamic Plugin SDK.
See `docs/design/` for full design specs.

## Writing Style

No em dashes (`—`). Use commas, periods, or parentheses instead.

## Knowledge Base

| File | Purpose |
Expand Down
59 changes: 34 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,47 @@ A Functions-as-a-Service PoC UI for the OpenShift Web Console. Developers create

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.

## Prerequisites
## Deployment on cluster

### Prerequisites

- [oc](https://console.redhat.com/openshift/downloads) CLI
- An [OpenShift 4.19 cluster](https://console.redhat.com/openshift/create)

### Quick install

```shell
oc new-project console-functions-plugin
oc apply -f https://twogiants.github.io/func-console/plugin.yaml
```

### Manual install (requires [Helm](https://helm.sh))

```shell
oc new-project console-functions-plugin
Comment thread
matejvasek marked this conversation as resolved.
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>"
```

To deploy a specific build, use its git commit SHA as the tag:

```shell
--set "plugin.image=ghcr.io/twogiants/console-functions-plugin:sha-<commit>"
```

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.

## Development

### Prerequisites

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

## Development

### Option 1: Local

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

## Deployment on cluster

A [Helm](https://helm.sh) chart is available to deploy the plugin to an OpenShift environment.

The following Helm parameters are required:

`plugin.image`: The location of the image containing the plugin that was previously pushed

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.

### Installing the Helm Chart

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:

```shell
helm upgrade -i my-plugin charts/openshift-console-plugin -n my-namespace --create-namespace --set plugin.image=my-plugin-image-location
```

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.

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.

## i18n

The plugin uses [react-i18next](https://react.i18next.com/) for translations. The i18n namespace must match
Expand Down
2 changes: 1 addition & 1 deletion docs/WORKFLOW.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ For each comment: read the full text and its diff hunk context, make the fix, th

## Branching

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.
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.

## Pull Requests

Expand Down
20 changes: 20 additions & 0 deletions docs/claude-progress.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
# Claude Progress Log
# Newest entries first. Agents: append your entry at the top after the header.

---
## 2026-04-20 | Session: CI/CD pipeline and ESLint fixes
Worked on: GitHub Actions CI/CD pipeline, ESLint config fixes, README restructure
Completed:
- 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)
- Multi-arch builds (amd64, arm64, ppc64le, s390x) via docker/setup-qemu-action + docker/setup-buildx-action, required for OCP
- Build attestation signing via actions/attest-build-provenance, required for OCP
- OCI annotations on image index (description, source, vendor, url), following knative/func patterns
- Docker layer caching via GHA cache (build-image writes, publish reads)
- Follows knative/func patterns: top-level permissions (id-token, contents, packages, attestations), concurrency groups, cancel-in-progress for PRs
- 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)
- Added Jest globals block for test files
- Downgraded @console/pluginAPI shared dep to >=4.19.0
- Restructured README: deployment section moved to top with OCP 4.19 prerequisite, GHCR registry link, separate prerequisites for deployment and development
- Added hack/next-plan-number.sh for deterministic plan/branch numbering based on remote PR count
- Updated WORKFLOW.md branching convention to use the helper script
- 8 suites, 34 tests, all passing, zero lint errors
Left off: PR #10 open. User needs to enable GITHUB_TOKEN write permissions in repo Settings and add branch protection rule for master.
Blockers: None

---
## 2026-04-17 | Session: FaaS route rename and nav restructure
Worked on: Rename routes from /functions to /faas, restructure nav for both perspectives
Expand Down
28 changes: 27 additions & 1 deletion docs/features.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,9 @@
"UserAvatar is clickable only on the Function List Page, clicking reopens PatModal to change the PAT and associated GitHub user",
"On Create and Edit pages, UserAvatar displays the GitHub user but is not clickable (PAT cannot be changed from those pages)",
"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",
"PAT change logic is encapsulated in a useUserAvatar custom hook following layered architecture (Hook imports Service, Component imports Hook)"
"PAT change logic is encapsulated in a useUserAvatar custom hook following layered architecture (Hook imports Service, Component imports Hook)",
"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.",
"The GH PAT must not be compiled/hardcode into code at compile time."
],
"passes": false
},
Expand All @@ -124,5 +126,29 @@
"Deployed functions without a matching repo still appear in the table with available cluster data (name, namespace, status, replicas, url)"
],
"passes": false
},
{
"category": "technical",
"description": "CI/CD: GitHub Actions pipelines for PR checks and master publish to GHCR, plus lint fixes and README deployment instructions",
"steps": [
"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",
"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",
"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)",
"Both pipelines authenticate to GHCR using GITHUB_TOKEN secret with packages:write permission (token added to repo's Actions secrets)",
"Add yarn lint script to package.json if missing, run it, and fix all lint errors in the codebase",
"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>"
],
"passes": true
},
{
"category": "functional",
"description": "Set GitHub Secret (KUBECONFIG) on created function repos so GH Actions can deploy to the cluster",
"steps": [
"Add createSecret method to SourceControlService interface",
"Encrypt secret value with repo public key using tweetnacl or libsodium.js",
"Wire into create flow: after repo creation and file push, set KUBECONFIG secret on the repo",
"GH Actions workflow can authenticate to the cluster and run func deploy"
],
"passes": false
}
]
Loading