Skip to content

Commit

Permalink
V2 (#207)
Browse files Browse the repository at this point in the history
* chore: Remove deprecated option

* chore: Update to v2

- Replace Yarn with PNPM
- Update Docker base image
- Transpile to ESM
- Replace Jest with Vitest (wip)

* chore: Remove Husky hook

* chore: Build on PRs

* chore: Install git

* chore: Safelist the GHA workspace directory

* chore: Use standard base image

* chore: Workdir & mount point

* chore: Dubious ownership needs to be fixed at runtime

* chore: Formatting

* chore: Update dependencies

* chore: Dual push to GHCR

* chore: Add OCI labels

* chore: Follow Docker docs for multi-registry

* chore: Simplify git tag

* fix: Defaults for boolean inputs

* doc: Update latest

* chore: Add funding metadata
  • Loading branch information
franky47 authored Apr 9, 2024
1 parent f283bd3 commit 722af6e
Show file tree
Hide file tree
Showing 14 changed files with 3,295 additions and 5,371 deletions.
3 changes: 3 additions & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
github: [franky47]
liberapay: francoisbest
custom: ['https://paypal.me/francoisbest?locale.x=fr_FR']
111 changes: 83 additions & 28 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,42 +13,97 @@ jobs:
name: Integration
runs-on: ubuntu-latest
steps:
- id: yarn-cache
name: Get Yarn cache path
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/checkout@a81bbbf8298c0fa03ea29cdc473d45769f953675
- uses: actions/setup-node@56899e050abffc08c2b3b61f3ec6a79a9dc3223d
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d
with:
node-version: 16.x
- uses: actions/cache@d1255ad9362389eac595a9ae406b8e8cb3331f16
name: Load Yarn cache
version: 8
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- run: yarn install --ignore-scripts
name: Install dependencies
- run: yarn ci
name: Run integration tests
node-version: lts/*
cache: pnpm
- name: Install dependencies
run: pnpm install --ignore-scripts
- name: Run integration tests
run: pnpm run test

cd:
name: Deployment
needs: ci
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@a81bbbf8298c0fa03ea29cdc473d45769f953675
- uses: manusa/actions-publish-docker@db938e45d2a3487e0eab9646e83550f554c17af3
name: Build & publish Docker image
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- id: docker-tag
run: |
tag=$( \
echo ${{ github.ref_name }} \
| sed 's#refs/heads/##g' \
| sed 's#refs/tags/##g' \
| sed 's#refs/pull/##g' \
| tr '/' '_' \
| tr -d '#' \
)
if [ "$tag" == "master" ]; then
echo "tag=latest" >> $GITHUB_OUTPUT
else
echo "tag=$tag" >> $GITHUB_OUTPUT
fi
- id: package
run: echo "version=$(cat package.json | jq -r .version)" >> $GITHUB_OUTPUT
- name: Collect Docker labels & tags
id: docker-labels-tags
run: |
echo 'labels<<__LABELS_EOF__' >> $GITHUB_OUTPUT
echo "org.opencontainers.image.title=47ng/actions-clever-cloud" >> $GITHUB_OUTPUT
echo "org.opencontainers.image.description=GitHub action to deploy to Clever Cloud" >> $GITHUB_OUTPUT
echo "org.opencontainers.image.version=${{ steps.package.outputs.version }}" >> $GITHUB_OUTPUT
echo "org.opencontainers.image.revision=${{ github.sha }}" >> $GITHUB_OUTPUT
echo "org.opencontainers.image.licenses=MIT" >> $GITHUB_OUTPUT
echo "org.opencontainers.image.source=https//github.com/${{github.repository}}/tree/${{ github.sha }}" >> $GITHUB_OUTPUT
echo "org.opencontainers.image.documentation=https://github.com/${{github.repository}}/blob/master/packages/server/README.md" >> $GITHUB_OUTPUT
echo "org.opencontainers.image.url=https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}" >> $GITHUB_OUTPUT
echo '__LABELS_EOF__' >> $GITHUB_OUTPUT
echo 'tags<<__TAGS_EOF__' >> $GITHUB_OUTPUT
echo "47ng/actions-clever-cloud:${{ steps.docker-tag.outputs.tag }}" >> $GITHUB_OUTPUT
echo "47ng/actions-clever-cloud:${{ steps.package.outputs.version }}" >> $GITHUB_OUTPUT
echo "47ng/actions-clever-cloud:git-${{ github.sha }}" >> $GITHUB_OUTPUT
echo "ghcr.io/47ng/actions-clever-cloud:${{ steps.docker-tag.outputs.tag }}" >> $GITHUB_OUTPUT
echo "ghcr.io/47ng/actions-clever-cloud:${{ steps.package.outputs.version }}" >> $GITHUB_OUTPUT
echo "ghcr.io/47ng/actions-clever-cloud:git-${{ github.sha }}" >> $GITHUB_OUTPUT
echo '__TAGS_EOF__' >> $GITHUB_OUTPUT
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
name: 47ng/actions-clever-cloud
username: ${{ secrets.DOCKER_HUB_USER }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
tag script: |
const tag = context.ref
.replace('refs/heads/', '')
.replace('refs/tags/', '')
.replace('refs/pull/', '')
.replace(/\//g, '_')
.replace(/#/g, '');
return tag === 'master' ? 'latest' : tag;
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
id: docker-build-push
uses: docker/build-push-action@v5
with:
context: .
labels: '${{ steps.docker-labels-tags.outputs.labels }}'
tags: '${{ steps.docker-labels-tags.outputs.tags }}'
push: true
- name: Generate step summary
run: |
echo "## 🐳 &nbsp;Docker image" >> $GITHUB_STEP_SUMMARY
echo "Digest: \`${{ steps.docker-build-push.outputs.digest }}\`" >> $GITHUB_STEP_SUMMARY
echo "### 📌 &nbsp;Tags" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "${{ steps.docker-labels-tags.outputs.tags }}" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "### 🏷 &nbsp;Labels" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "${{ steps.docker-labels-tags.outputs.labels }}" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
4 changes: 0 additions & 4 deletions .husky/pre-push

This file was deleted.

23 changes: 16 additions & 7 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
FROM node:16-bullseye AS builder
FROM node:20-slim AS builder

WORKDIR /action

COPY package.json yarn.lock ./
COPY package.json pnpm-lock.yaml ./

RUN yarn
RUN corepack enable
RUN pnpm install
COPY src ./src
COPY tsconfig.json ./
RUN yarn build
RUN pnpm build
RUN rm -rf node_modules
RUN yarn install --production
RUN pnpm install --frozen-lockfile --prod

# ---

FROM node:16-bullseye AS final
FROM node:20-slim AS final

COPY --from=builder /action /action
RUN apt update && apt install -y git

# Provide defaults for boolean inputs so the parser doesn't complain
ENV INPUT_QUIET false
ENV INPUT_FORCE false

COPY --from=builder /action/package.json /action/package.json
COPY --from=builder /action/node_modules /action/node_modules
COPY --from=builder /action/dist /action/dist

CMD node /action/dist/main.js
32 changes: 17 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
# Deploy to Clever Cloud

[![Marketplace](https://img.shields.io/github/v/release/47ng/actions-clever-cloud?label=Marketplace)](https://github.com/marketplace/actions/deploy-to-clever-cloud)
[![MIT License](https://img.shields.io/github/license/47ng/actions-clever-cloud.svg?color=blue)](https://github.com/47ng/actions-clever-cloud/blob/master/LICENSE)
[![MIT License](https://img.shields.io/github/license/47ng/actions-clever-cloud.svg?color=blue&label=License)](https://github.com/47ng/actions-clever-cloud/blob/master/LICENSE)
[![CI/CD](https://github.com/47ng/actions-clever-cloud/workflows/CI/CD/badge.svg)](https://github.com/47ng/actions-clever-cloud/actions)
[![Average issue resolution time](https://isitmaintained.com/badge/resolution/47ng/actions-clever-cloud.svg)](https://isitmaintained.com/project/47ng/actions-clever-cloud)
[![Number of open issues](https://isitmaintained.com/badge/open/47ng/actions-clever-cloud.svg)](https://isitmaintained.com/project/47ng/actions-clever-cloud)
[![GitHub Sponsors](https://img.shields.io/github/sponsors/franky47?color=%23db61a2&label=Sponsors)](https://github.com/sponsors/franky47)

GitHub action to deploy your application to
[Clever Cloud](https://clever-cloud.com).
GitHub action to deploy your application to [Clever Cloud](https://clever-cloud.com).

## Prerequisite

Expand Down Expand Up @@ -42,7 +40,7 @@ steps:
fetch-depth: 0

# Deploy your application
- uses: 47ng/actions-clever-cloud@v1.3.1
- uses: 47ng/actions-clever-cloud@v2.0.0
env:
CLEVER_TOKEN: ${{ secrets.CLEVER_TOKEN }}
CLEVER_SECRET: ${{ secrets.CLEVER_SECRET }}
Expand All @@ -62,7 +60,7 @@ If you have committed the `.clever.json` file, you only need to specify
the alias of the application to deploy:

```yml
- uses: 47ng/actions-clever-cloud@v1.3.1
- uses: 47ng/actions-clever-cloud@v2.0.0
with:
alias: my-app-alias
env:
Expand All @@ -74,7 +72,7 @@ If you don't have this `.clever.json` file or you want to explicly
deploy to another application, you can pass its ID:

```yml
- uses: 47ng/actions-clever-cloud@v1.3.1
- uses: 47ng/actions-clever-cloud@v2.0.0
with:
appID: app_facade42-cafe-babe-cafe-deadf00dbaad
env:
Expand Down Expand Up @@ -116,7 +114,7 @@ You can set extra environment variables on the deployed application under the
key=value).

```yml
- uses: 47ng/actions-clever-cloud@v1.3.1
- uses: 47ng/actions-clever-cloud@v2.0.0
with:
setEnv: | # <- note the pipe here..
FOO=bar
Expand Down Expand Up @@ -156,7 +154,7 @@ you can specify a timeout in seconds after which the workflow will move on,
regardless of the deployment status:

```yml
- uses: 47ng/actions-clever-cloud@v1.3.1
- uses: 47ng/actions-clever-cloud@v2.0.0
with:
timeout: 1800 # wait at maximum 30 minutes before moving on
env:
Expand All @@ -171,7 +169,7 @@ regardless of the deployment status:
Clever Cloud uses a Git remote to perform deploys. By default, if the commit you want to deploy is not a fast-forward from the commit currently deployed, the deploy will be rejected. You can pass `force: true` to force the deploy anyway:

```yml
- uses: 47ng/actions-clever-cloud@v1.3.1
- uses: 47ng/actions-clever-cloud@v2.0.0
with:
appID: app_facade42-cafe-babe-cafe-deadf00dbaad
force: true
Expand All @@ -187,7 +185,7 @@ Clever Cloud uses a Git remote to perform deploys. By default, if the commit you
You can write the deployment logs to a file for archiving:

```yml
- uses: 47ng/actions-clever-cloud@v1.3.1
- uses: 47ng/actions-clever-cloud@v2.0.0
with:
logFile: ./clever-cloud-deploy.log
env:
Expand All @@ -206,7 +204,7 @@ If your deployment process is susceptible to log secrets or PII, you can also
disable it from printing onto the console, using the `quiet` option:

```yml
- uses: 47ng/actions-clever-cloud@v1.3.1
- uses: 47ng/actions-clever-cloud@v2.0.0
with:
quiet: true
env:
Expand All @@ -227,7 +225,7 @@ _Note: this behaviour will be disabled if the `quiet` option is used._
This action follows [SemVer](https://semver.org/).

To specify the version of the action to use:
- `uses: 47ng/actions-clever-cloud@v1.3.1`: latest stable version
- `uses: 47ng/actions-clever-cloud@v2.0.0`: latest stable version
- `uses: 47ng/actions-clever-cloud@3e5402496b8d6492401ebb3134acfeccc25c3fce`: pinned to a specific Git SHA-1 (check out the [releases](https://github.com/47ng/actions-clever-cloud/releases))
- `uses: docker://ghcr.io/47ng/actions-clever-cloud:latest`: latest code from master (not recommended, as it may break: hic sunt dracones.)

Expand All @@ -237,9 +235,13 @@ To specify the version of the action to use:
>
> If you wish to test unreleased features, go through Docker directly.

> **Note**: as of 2023-03-24, Docker images have been moved from Docker Hub
> **Note**: as of 2023-03-24, Docker images have been copied from Docker Hub
> (`47ng/actions-clever-cloud`) to GitHub Container Registry (`ghcr.io/47ng/actions-clever-cloud`),
> in response to Docker's plan to delete open source organisations on free plans.
>
> Although they backtracked on this decision, the images are now dual-published
> on both platforms, and default to being downloaded from GitHub Container Registry
> for (seemingly) better performance.

## Why ?

Expand Down
28 changes: 16 additions & 12 deletions __tests__/main.test.ts → __tests__/main.test.ts.disabled
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
// @ts-check

import * as core from '@actions/core'
import * as exec from '@actions/exec'
import { expect, test, vi } from 'vitest'
import run from '../src/action'

const core = require('@actions/core')
const { exec } = require('@actions/exec')

jest.mock('@actions/exec')
jest.mock('@actions/core')

// --

function expectCleverCLICallWithArgs(
callIndex: number,
...expectedArgs: any[]
) {
const cli = exec.mock.calls[callIndex][0]
const args = exec.mock.calls[callIndex][1]
const _exec = vi.spyOn(exec, 'exec')
const cli = _exec.mock.calls[callIndex]?.[0]
const args = _exec.mock.calls[callIndex]?.[1]
expect(cli).toEqual('clever')
expectedArgs.map((arg, i) => {
expect(args[i]).toEqual(arg)
expect(args?.[i]).toEqual(arg)
})
}

test('deploy default application (no arguments)', async () => {
exec.mockResolvedValue(0)
vi.mock('@actions/exec', () => ({
exec: () => Promise.resolve(0)
}))
await run({
token: 'token',
secret: 'secret',
Expand Down Expand Up @@ -173,7 +173,9 @@ test('passing extra env variables, using alias only', async () => {
})

test('deployment failure fails the workflow', async () => {
exec.mockResolvedValue(42)
vi.mock('@actions/exec', () => ({
exec: () => Promise.resolve(42)
}))
await run({
token: 'token',
secret: 'secret',
Expand All @@ -183,7 +185,9 @@ test('deployment failure fails the workflow', async () => {
})

test('deployment failure with timeout fails the workflow', async () => {
exec.mockResolvedValue(42)
vi.mock('@actions/exec', () => ({
exec: () => Promise.resolve(42)
}))
await run({
token: 'token',
secret: 'secret',
Expand Down
3 changes: 2 additions & 1 deletion __tests__/processArguments.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { afterEach, beforeEach, expect, test, vitest, } from 'vitest'
import { processArguments } from '../src/action'

// --

const OLD_ENV = process.env

beforeEach(() => {
jest.resetModules() // this is important - it clears the cache
vitest.resetModules() // this is important - it clears the cache
process.env = { ...OLD_ENV }
// Simulate default values
process.env.INPUT_FORCE = 'false'
Expand Down
8 changes: 1 addition & 7 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,6 @@ inputs:
description: |
Don't print deployment output to the console. Use this in case your deployment
may reveal secrets or PII.
extraEnvSafelist:
required: false
deprecationMessage: This is no longer needed or used, use the `setEnv` input instead.
description: |
A comma-separated list of extra environment variable names to allow
to be set, see https://github.com/47ng/ations-clever-cloud#safelisting
runs:
using: docker
image: docker://ghcr.io/47ng/actions-clever-cloud:v1.3.1
image: docker://ghcr.io/47ng/actions-clever-cloud:v2.0.0
Loading

0 comments on commit 722af6e

Please sign in to comment.