diff --git a/.github/workflows/build-image-degit.yml b/.github/workflows/build-image-degit.yml new file mode 100644 index 0000000000..918da1b1f4 --- /dev/null +++ b/.github/workflows/build-image-degit.yml @@ -0,0 +1,33 @@ +name: đŸ“Ļ Build Docker Image Degit 📁 + +on: + push: + branches: + - '**' + - '!master' + tags: + - '**' + paths: + - .github/kontinuousVersion + - packages/degit + +concurrency: + cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.event.ref }} + +jobs: + build-base-images: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Build image + uses: ./.github/actions/build-images + with: + token: ${{ secrets.GITHUB_TOKEN }} + dockerfile: packages/degit/Dockerfile + destination: /degit + \ No newline at end of file diff --git a/.github/workflows/build-image-kontinuous.yml b/.github/workflows/build-image-kontinuous.yml new file mode 100644 index 0000000000..1a3e84e426 --- /dev/null +++ b/.github/workflows/build-image-kontinuous.yml @@ -0,0 +1,69 @@ +name: đŸ“Ļ Build Docker Image Kontinuous đŸĨˇ + +on: + push: + branches: + - '**' + - '!master' + tags: + - '**' + paths: + - .github/kontinuousVersion + - packages/kontinuous/** + - packages/common/** + - packages/helm-tree/** + - plugins/** + - .github/actions/** + - yarn.lock + - .yarnrc.yml + +concurrency: + cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.event.ref }} + +jobs: + build-base-images: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Build image + uses: ./.github/actions/build-images + with: + token: ${{ secrets.GITHUB_TOKEN }} + dockerfile: packages/kontinuous/Dockerfile + destination: "" + + build-actions: + needs: [build-base-images] + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + strategy: + fail-fast: false + matrix: + include: + - destination: "/deploy-via-github" + dockerfile: .github/actions/deploy-via-github/Dockerfile + context: .github/actions/deploy-via-github + - destination: "/deploy-via-webhook" + dockerfile: .github/actions/deploy-via-webhook/Dockerfile + context: .github/actions/deploy-via-webhook + - destination: "/env" + dockerfile: .github/actions/env/Dockerfile + context: .github/actions/env + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Build image + uses: ./.github/actions/build-images + with: + token: ${{ secrets.GITHUB_TOKEN }} + context: ${{ matrix.context }} + dockerfile: ${{ matrix.dockerfile }} + destination: ${{ matrix.destination }} + \ No newline at end of file diff --git a/.github/workflows/build-image-wait-needs.yml b/.github/workflows/build-image-wait-needs.yml new file mode 100644 index 0000000000..fc20116292 --- /dev/null +++ b/.github/workflows/build-image-wait-needs.yml @@ -0,0 +1,37 @@ +name: đŸ“Ļ Build Docker Image Wait-needs ⌛ + +on: + push: + branches: + - '**' + - '!master' + tags: + - '**' + paths: + - .github/kontinuousVersion + - packages/wait-needs/** + - packages/common/** + - packages/helm-tree/** + - yarn.lock + - .yarnrc.yml + +concurrency: + cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.event.ref }} + +jobs: + build-base-images: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Build image + uses: ./.github/actions/build-images + with: + token: ${{ secrets.GITHUB_TOKEN }} + dockerfile: packages/wait-needs/Dockerfile + destination: /wait-needs + \ No newline at end of file diff --git a/.github/workflows/build-image-webhook.yml b/.github/workflows/build-image-webhook.yml new file mode 100644 index 0000000000..f0eb8c559d --- /dev/null +++ b/.github/workflows/build-image-webhook.yml @@ -0,0 +1,37 @@ +name: đŸ“Ļ Build Docker Image Webhook đŸĒ + +on: + push: + branches: + - '**' + - '!master' + tags: + - '**' + paths: + - .github/kontinuousVersion + - packages/webhook/** + - packages/common/** + - packages/helm-tree/** + - yarn.lock + - .yarnrc.yml + +concurrency: + cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.event.ref }} + +jobs: + build-base-images: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Build image + uses: ./.github/actions/build-images + with: + token: ${{ secrets.GITHUB_TOKEN }} + dockerfile: packages/webhook/Dockerfile + destination: /webhook + \ No newline at end of file diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000000..3deaccbada --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,72 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: ✅ CodeQL 📝 + +on: + push: + branches: [ "master" ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "master" ] + schedule: + - cron: '29 14 * * 4' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'javascript' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # ℹī¸ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/release-commit.yml b/.github/workflows/release-commit.yml new file mode 100644 index 0000000000..a470168396 --- /dev/null +++ b/.github/workflows/release-commit.yml @@ -0,0 +1,51 @@ +name: 🎉 Release Commit + +on: + workflow_dispatch: + pull_request: + types: [closed] + + +concurrency: + cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.ref_name }} + +jobs: + yarn-release: + if: github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true + runs-on: ubuntu-latest + name: Create release using commit-and-tag-version + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + token: ${{ secrets.SOCIALGROOVYBOT_BOTO_PAT }} + + - name: Install dependencies + run: yarn --immutable + + - name: Import GPG key + uses: crazy-max/ghaction-import-gpg@v5 + with: + gpg_private_key: ${{ secrets.SOCIALGROOVYBOT_GPG_PRIVATE_KEY }} + passphrase: ${{ secrets.SOCIALGROOVYBOT_GPG_PASSPHRASE }} + git_user_signingkey: true + git_commit_gpgsign: true + git_push_gpgsign: false + git_tag_gpgsign: true + + - name: Run release + env: + GIT_AUTHOR_EMAIL: ${{ secrets.SOCIALGROOVYBOT_EMAIL }} + GIT_AUTHOR_NAME: ${{ secrets.SOCIALGROOVYBOT_NAME }} + GIT_COMMITTER_EMAIL: ${{ secrets.SOCIALGROOVYBOT_EMAIL }} + GIT_COMMITTER_NAME: ${{ secrets.SOCIALGROOVYBOT_NAME }} + run: yarn release + + - name: Push release + shell: bash + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git remote set-url --push origin https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git + git push -f --follow-tags origin master \ No newline at end of file diff --git a/.github/workflows/release-publish.yml b/.github/workflows/release-publish.yml new file mode 100644 index 0000000000..eab9bc2cb9 --- /dev/null +++ b/.github/workflows/release-publish.yml @@ -0,0 +1,67 @@ +name: ✨ Release Publish + +on: + push: + tags: + - v*.* + +concurrency: + cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.ref_name }} + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - uses: actions/setup-node@v3 + with: + node-version: 20 + cache: 'yarn' + + - name: yarn install + shell: bash + run: yarn --immutable + + - name: build with ncc + shell: bash + run: yarn workspace kontinuous build + + - name: prepublish + shell: bash + run: | + cp LICENSE README.md packages/kontinuous/ + cat <<< $(jq "del(.dependencies, .devDependencies, .scripts, .main)" packages/kontinuous/package.json) > packages/kontinuous/package.json + + - name: extract npm tag + id: npm-tag + shell: bash + run: | + if [[ "$GITHUB_REF" == *"alpha"* ]]; then + npm_tag="alpha" + elif [[ "$GITHUB_REF" == *"beta"* ]]; then + npm_tag="beta" + else + npm_tag="latest" + fi + echo "tag=$npm_tag" >> $GITHUB_OUTPUT + + - id: publish-kontinuous + uses: JS-DevTools/npm-publish@v2 + with: + token: ${{ secrets.SOCIALGROOVYBOT_NPM_TOKEN }} + package: packages/kontinuous/package.json + tag: ${{ steps.npm-tag.outputs.tag }} + + - if: steps.publish-kontinuous.outputs.type + run: | + echo "Version changed: ${{ steps.publish-kontinuous.outputs.old-version }} => ${{ steps.publish-kontinuous.outputs.version }}" + + - name: Release + uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/') + with: + token: ${{ secrets.SOCIALGROOVYBOT_BOTO_PAT }} + generate_release_notes: true diff --git a/.github/workflows/review-e2e-linked.yml b/.github/workflows/review-e2e-linked.yml new file mode 100644 index 0000000000..8ff10197cf --- /dev/null +++ b/.github/workflows/review-e2e-linked.yml @@ -0,0 +1,58 @@ +name: 🏗ī¸ Review e2e linked + +on: + create + +concurrency: + cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.ref_name }} + +jobs: + link-e2e: + name: Link e2e if match dev-** + runs-on: ubuntu-latest + steps: + - id: vars + name: Branch check convention + run: | + GIT_BRANCH=${GITHUB_REF#refs/heads/} + if [[ "$GIT_BRANCH" =~ ^dev-.* ]]; then + ok=yes + else + ok=no + fi + echo "branch=$GIT_BRANCH" >> $GITHUB_OUTPUT + echo "ok=$ok" >> $GITHUB_OUTPUT + + - name: Checkout repository + if: steps.vars.outputs.ok == 'yes' + uses: actions/checkout@v3 + with: + token: ${{ secrets.SOCIALGROOVYBOT_BOTO_PAT }} + ref: ${{ steps.vars.output.branch }} + + - name: Install dependencies + if: steps.vars.outputs.ok == 'yes' + run: yarn --immutable + + - name: Run e2e link + if: steps.vars.outputs.ok == 'yes' + env: + GIT_AUTHOR_EMAIL: ${{ secrets.SOCIALGROOVYBOT_EMAIL }} + GIT_AUTHOR_NAME: ${{ secrets.SOCIALGROOVYBOT_NAME }} + GIT_COMMITTER_EMAIL: ${{ secrets.SOCIALGROOVYBOT_EMAIL }} + GIT_COMMITTER_NAME: ${{ secrets.SOCIALGROOVYBOT_NAME }} + shell: bash + run: | + yarn version-e2e:set + GIT_BRANCH=${GITHUB_REF#refs/heads/} + git commit -am "chore: link to branch $GIT_BRANCH" + + - name: Push e2e linked to current branch + if: steps.vars.outputs.ok == 'yes' + shell: bash + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git remote set-url --push origin https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git + git push \ No newline at end of file diff --git a/.github/workflows/sync-gitlab.yml b/.github/workflows/sync-gitlab.yml new file mode 100644 index 0000000000..0bdd378aad --- /dev/null +++ b/.github/workflows/sync-gitlab.yml @@ -0,0 +1,24 @@ +name: đŸĻŠ Mirror and run GitLab CI + +on: + push: + branches: + - master + tags: + - "**" + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Mirror + trigger CI + uses: socialgouv/gitlab-mirror-and-ci-action@v1 + with: + args: "https://gitlab.fabrique.social.gouv.fr/SRE/kontinuous" + env: + GITLAB_HOSTNAME: "gitlab.fabrique.social.gouv.fr" + GITLAB_USERNAME: "oauth2" + GITLAB_PASSWORD: ${{ secrets.GITLAB_TOKEN }} + GITLAB_PROJECT_ID: "189" + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/tests-build.yml b/.github/workflows/tests-build.yml new file mode 100644 index 0000000000..037d9c7d07 --- /dev/null +++ b/.github/workflows/tests-build.yml @@ -0,0 +1,46 @@ +name: ✅ Tests build 📃 + +on: + push: + branches: + - "**" + - "!v*" + tags-ignore: + - "**" + +concurrency: + cancel-in-progress: true + group: tests-build-${{ github.ref_name }} + +jobs: + tests: + name: Tests + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - nodeVersion: 16.17 # minimum requirement + - nodeVersion: 18 + - nodeVersion: 20 + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.nodeVersion }} + cache: 'yarn' + + - name: Yarn install + run: | + yarn workspaces focus kontinuous + + - name: Run tests + run: yarn workspace kontinuous test + + - name: Run plugins contrib + run: | + yarn --cwd plugins/contrib + yarn --cwd plugins/contrib test diff --git a/.github/workflows/tests-deploy.yaml b/.github/workflows/tests-deploy.yaml new file mode 100644 index 0000000000..e78725e373 --- /dev/null +++ b/.github/workflows/tests-deploy.yaml @@ -0,0 +1,108 @@ +name: ✅ Tests deploy 🚀 + +on: + push: + branches: + - "**" + - "!v*" + tags-ignore: + - "**" + +concurrency: + cancel-in-progress: true + group: tests-deploy-${{ github.ref_name }} + +jobs: + test-kind-deployment: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + nodeVersion: [16.17, 18, 20] + testParams: + - cwd: .github/e2e/standalone-charts + testScript: | + kubectl get jobs -n test-project-ci + kubectl get jobs -n test-project-ci --field-selector status.successful=1 | grep "extra-job" # additionnal grep to exit 1 on error + + - cwd: .github/e2e/values-js + testScript: | + kubectl get pods -n test-namespace + kubectl get pods -n test-namespace --field-selector=status.phase=Running | grep "app" + kubectl get ingress -n test-namespace --field-selector metadata.name=app -o=jsonpath='{.items[0].spec.rules[0].host}' | grep "test.demo.net" + + - cwd: .github/e2e/app-simple + inlineValues: | + app: + image: nginx + containerPort: 80 + testScript: | + kubectl get pods -n kontinuous + kubectl get pods -n kontinuous --field-selector=status.phase=Running | grep "app" + + - cwd: .github/e2e/app-simple + inlineValues: | + global: + imageRepository: "" + app: + imagePackage: nginx + imageRepository: "" + registry: docker.io + containerPort: 80 + imageTag: 1.21.6 + testScript: | + kubectl get pods -n kontinuous + kubectl get pods -n kontinuous --field-selector=status.phase=Running | grep "app" + kubectl get pods -n kontinuous --field-selector=status.phase=Running -o jsonpath="{.items[*].spec.containers[*].image}" | grep "docker.io/nginx:1.21.6" + + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.nodeVersion }} + cache: 'yarn' + + - name: Yarn install + run: | + yarn workspaces focus kontinuous --production + + - name: Kubernetes KinD Cluster + uses: helm/kind-action@v1.5.0 + - name: prepare kontinuous + shell: bash + run: | + mkdir -p $HOME/.kontinuous + + echo " + links: + socialgouv/kontinuous: ${GITHUB_WORKSPACE} + " > $HOME/.kontinuous/config.yaml + + kubectl cluster-info + kubectl version + kubectl get pods -n kube-system + kubectl create ns test-project-ci + + - name: test deploy-via-github + shell: bash + env: + KS_DEBUG: "true" + KS_KUBECONFIG_CONTEXT: kind-chart-testing + KS_CI_NAMESPACE: test-project-ci + RANCHER_PROJECT_ID: "cluster:project" + KS_ENVIRONMENT: prod + KS_INLINE_SET: | + global.antiAffinity.enabled: false + KS_INLINE_VALUES: | + ${{ matrix.testParams.inlineValues || '' }} + KS_WORKSPACE_PATH: ${{ matrix.testParams.cwd }} + KS_INLINE_CONFIG_SET: | + dependencies.fabrique.dependencies.contrib.preDeploy.cleanOrphan.options.crdApiResources: [] + run: ./kontinuous deploy + + - name: run test script + shell: bash + run: | + set -e + ${{ matrix.testParams.testScript }} diff --git a/.github/workflows/tests-kubeconform.yml b/.github/workflows/tests-kubeconform.yml new file mode 100644 index 0000000000..7eed07f502 --- /dev/null +++ b/.github/workflows/tests-kubeconform.yml @@ -0,0 +1,71 @@ +name: ✅ Tests kubeconform 📚 + +on: + workflow_dispatch: + push: + branches: + - "**" + - "!v*" + tags-ignore: + - "**" + paths: + - "./packages/kontinuous/tests/**" + - ".github/workflows/tests-kubeconform.yml" + +concurrency: + cancel-in-progress: true + group: tests-kubeconform-${{ github.ref_name }} + +jobs: + tests-kubeconform: + name: Tests-kubeconform + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: install kubeconform + shell: bash + run: | + sudo apt-get update + sudo apt-get install -y wget + wget https://github.com/yannh/kubeconform/releases/download/v0.6.1/kubeconform-linux-amd64.tar.gz -O kubeconform-linux-amd64.tar.gz + tar -xzvf kubeconform-linux-amd64.tar.gz + ./kubeconform -v + + - name: extract YAML from snapshots + shell: bash + run: | + mkdir tests_yaml + for f in ./packages/kontinuous/tests/__snapshots__/*.yaml; do + echo "Processing $f file..."; + BASENAME=$(basename "$f"); + node -e "x=require(\"$f\"); console.log(Object.values(x)[0].trim().slice(1,-1))" > "./tests_yaml/$BASENAME" + done + + - name: Run kubeconform on kube@1.24.9 + shell: bash + run: | + echo "Validate against kube API 1.24.9" + for f in ./tests_yaml/*.yaml; do + echo "$f" + ./kubeconform -summary -kubernetes-version 1.24.9 -strict -skip monitoring.coreos.com/v1/PodMonitor,postgresql.cnpg.io/v1/Pooler,postgresql.cnpg.io/v1/Cluster,bitnami.com/v1alpha1/SealedSecret "$f" + done + + - name: Run kubeconform on kube@1.25.7 + shell: bash + run: | + echo "Validate against kube API 1.25.7" + for f in ./tests_yaml/*.yaml; do + echo "$f" + ./kubeconform -summary -kubernetes-version 1.25.7 -skip monitoring.coreos.com/v1/PodMonitor,postgresql.cnpg.io/v1/Pooler,postgresql.cnpg.io/v1/Cluster,bitnami.com/v1alpha1/SealedSecret "$f" + done + + - name: Run kubeconform on kube@1.26.2 + shell: bash + run: | + echo "Validate against kube API 1.26.2" + for f in ./tests_yaml/*.yaml; do + echo "$f" + ./kubeconform -summary -kubernetes-version 1.26.2 -skip monitoring.coreos.com/v1/PodMonitor,postgresql.cnpg.io/v1/Pooler,postgresql.cnpg.io/v1/Cluster,bitnami.com/v1alpha1/SealedSecret "$f" + done diff --git a/.github/workflows/tests-lint.yml b/.github/workflows/tests-lint.yml new file mode 100644 index 0000000000..0b7a8222c3 --- /dev/null +++ b/.github/workflows/tests-lint.yml @@ -0,0 +1,33 @@ +name: ✅ Tests lint 🔲 + +on: + push: + branches: + - "**" + - "!v*" + tags-ignore: + - "**" + +concurrency: + cancel-in-progress: true + group: tests-lint-${{ github.ref_name }} + +jobs: + tests: + name: Lint + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - uses: actions/setup-node@v3 + with: + node-version: 20 + cache: 'yarn' + + - name: Yarn install + run: | + yarn --immutable + + - name: Run lint + run: yarn lint \ No newline at end of file diff --git a/.github/workflows/tests-webhook.yml b/.github/workflows/tests-webhook.yml new file mode 100644 index 0000000000..3d141dee5e --- /dev/null +++ b/.github/workflows/tests-webhook.yml @@ -0,0 +1,50 @@ +name: ✅ Tests webhook 🌍 + +on: + push: + branches: + - "**" + - "!v*" + tags-ignore: + - "**" + +concurrency: + cancel-in-progress: true + group: tests-webhook-${{ github.ref_name }} + +jobs: + tests: + name: Tests + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - nodeVersion: 16.17 # minimum requirement + - nodeVersion: 18 + - nodeVersion: 20 + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.nodeVersion }} + cache: 'yarn' + + - name: Yarn install + run: | + yarn workspaces focus ~webhook + + - name: write .kontinuous/config.yaml + shell: bash + run: | + mkdir -p $HOME/.kontinuous + echo " + links: + socialgouv/kontinuous: ${GITHUB_WORKSPACE} + " > $HOME/.kontinuous/config.yaml + + - name: Run tests + run: yarn workspace ~webhook test \ No newline at end of file