diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 99381bf..a850319 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,16 @@ name: LocalStack Test -on: [ push, pull_request ] +on: + push: + paths-ignore: + - ./*.md + - LICENSE + pull_request: + paths-ignore: + - ./*.md + - LICENSE + workflow_dispatch: + schedule: + - cron: '48 23 * * 0' jobs: localstack-action-test: @@ -8,18 +19,106 @@ jobs: steps: - uses: actions/checkout@v3 + # We must hack the action call as remote to be able to use the relative paths + # Could it break with different CWD? 🤔 - name: Start LocalStack - uses: ./ + uses: jenseng/dynamic-uses@v1 with: - image-tag: 'latest' - install-awslocal: 'true' - configuration: DEBUG=1 - use-pro: 'true' + uses: LocalStack/setup-localstack@${{ env.GH_ACTION_VERSION }} + with: |- + { + "image-tag": "latest", + "install-awslocal": "true", + "configuration": "DEBUG=1", + "use-pro": "true", + } env: LOCALSTACK_API_KEY: ${{ secrets.LOCALSTACK_API_KEY }} + GH_ACTION_VERSION: ${{ github.event_name == 'pull_request' && github.head_ref || github.ref_name }} - - name: Run Tests against LocalStack + - name: Run Tests Against LocalStack run: | awslocal s3 mb s3://test awslocal s3 ls echo "Test Execution complete!" + + cloud-pods-test: + name: 'Test Cloud Pods Action' + runs-on: ubuntu-latest + steps: + - name: ⚡️ Checkout the repository + uses: actions/checkout@v3 + + - name: Start LocalStack + uses: jenseng/dynamic-uses@v1 + with: + uses: LocalStack/setup-localstack@${{ env.GH_ACTION_VERSION }} + with: |- + { + "image-tag": "latest", + "install-awslocal": "true", + "configuration": "DEBUG=1", + "use-pro": "true", + } + env: + LOCALSTACK_API_KEY: ${{ secrets.LOCALSTACK_API_KEY }} + GH_ACTION_VERSION: ${{ github.event_name == 'pull_request' && github.head_ref || github.ref_name }} + + - name: Run AWS commands + run: | + awslocal s3 mb s3://test + awslocal sqs create-queue --queue-name test-queue + + - name: Save the Cloud Pod + uses: jenseng/dynamic-uses@v1 + with: + uses: LocalStack/setup-localstack@${{ env.GH_ACTION_VERSION }} + with: |- + { + "state-name": "cloud-pods-test", + "state-action": "save", + } + env: + LOCALSTACK_API_KEY: ${{ secrets.LOCALSTACK_API_KEY }} + GH_ACTION_VERSION: ${{ github.event_name == 'pull_request' && github.head_ref || github.ref_name }} + + local-state-test: + name: 'Test Local State Action' + runs-on: ubuntu-latest + steps: + - name: ⚡️ Checkout the repository + uses: actions/checkout@v3 + + - name: Start LocalStack + uses: jenseng/dynamic-uses@v1 + with: + uses: LocalStack/setup-localstack@${{ env.GH_ACTION_VERSION }} + with: |- + { + "image-tag": "latest", + "install-awslocal": "true", + "configuration": "DEBUG=1", + "use-pro": "true", + } + env: + LOCALSTACK_API_KEY: ${{ secrets.LOCALSTACK_API_KEY }} + GH_ACTION_VERSION: ${{ github.event_name == 'pull_request' && github.head_ref || github.ref_name }} + + - name: Run AWS Commands + run: | + awslocal s3 mb s3://test + awslocal sqs create-queue --queue-name test-queue + + - name: Save the State Artifact + uses: jenseng/dynamic-uses@v1 + with: + uses: LocalStack/setup-localstack@${{ env.GH_ACTION_VERSION }} + with: |- + { + "state-name": "cloud-pods-test", + "state-action": "save", + "state-backend": "local", + } + env: + LOCALSTACK_API_KEY: ${{ secrets.LOCALSTACK_API_KEY }} + GH_ACTION_VERSION: ${{ github.event_name == 'pull_request' && github.head_ref || github.ref_name }} diff --git a/.github/workflows/ephemeral.yml b/.github/workflows/ephemeral.yml new file mode 100644 index 0000000..cb378fb --- /dev/null +++ b/.github/workflows/ephemeral.yml @@ -0,0 +1,40 @@ +name: LocalStack Ephemeral Instance Test +on: pull_request + +jobs: + preview-test: + permissions: write-all + name: 'Test ephemeral instance workflow' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Deploy Ephemeral Instance + uses: jenseng/dynamic-uses@v1 + with: + uses: LocalStack/setup-localstack@${{ env.GH_ACTION_VERSION }} + with: |- + { + "github-token": "${{ secrets.GITHUB_TOKEN }}", + "state-backend": "ephemeral", + "state-action": "start", + "skip-ephemeral-stop": "true" + } + env: + LOCALSTACK_API_KEY: ${{ secrets.LOCALSTACK_API_KEY }} + GH_ACTION_VERSION: ${{ github.event_name == 'pull_request' && github.head_ref || github.ref_name }} + + # We want explicit shutdown + - name: Shutdown ephemeral instance + uses: jenseng/dynamic-uses@v1 + with: + uses: LocalStack/setup-localstack@${{ env.GH_ACTION_VERSION }} + with: |- + { + "github-token": "${{ secrets.GITHUB_TOKEN }}", + "state-backend": "ephemeral", + "state-action": "stop" + } + env: + LOCALSTACK_API_KEY: ${{ secrets.LOCALSTACK_API_KEY }} + GH_ACTION_VERSION: ${{ github.event_name == 'pull_request' && github.head_ref || github.ref_name }} diff --git a/README.md b/README.md index 1993dc3..17fc5be 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Setup LocalStack -[![LocalStack Test](https://github.com/HarshCasper/setup-localstack/actions/workflows/ci.yml/badge.svg)](https://github.com/HarshCasper/setup-localstack/actions/workflows/ci.yml) +[![LocalStack Test](https://github.com/LocalStack/setup-localstack/actions/workflows/ci.yml/badge.svg)](https://github.com/LocalStack/setup-localstack/actions/workflows/ci.yml) A GitHub Action to setup [LocalStack](https://github.com/localstack/localstack) on your GitHub Actions runner workflow by: @@ -8,34 +8,120 @@ A GitHub Action to setup [LocalStack](https://github.com/localstack/localstack) - Pulling a specific version of the LocalStack Docker Image into the GitHub Action runner. - Configuring the [LocalStack CLI](https://docs.localstack.cloud/get-started/#localstack-cli) to launch the Docker container with an optional API token for pro usage. - Installing [LocalStack AWS CLI](https://github.com/localstack/awscli-local), a thin wrapper around the `aws` command line interface for use with LocalStack to run integration tests over AWS services. +- Export/import [LocalStack state](https://docs.localstack.cloud/user-guide/state-management/export-import-state/) as an artifact +- Save/load [LocalStack Cloud Pods](https://docs.localstack.cloud/user-guide/state-management/cloud-pods/) +- Start/stop a [LocalStack Ephemeral Instance](https://docs.localstack.cloud/user-guide/cloud-sandbox/application-previews/) _(EXPERIMENTAL)_ ## Usage -To get started, you can use this minimal example: +### Get started with a minimal example ```yml - name: Start LocalStack - uses: HarshCasper/setup-localstack@v0.1.2 + uses: LocalStack/setup-localstack@v0.2.0 with: image-tag: 'latest' install-awslocal: 'true' env: LOCALSTACK_API_KEY: ${{ secrets.LOCALSTACK_API_KEY }} ``` +> **NOTE**: The `LOCALSTACK_API_KEY` environment variable is required to be set if `use-pro` is set to `true`. +If the key is not found LocalStack by default falls back to the CE edition and displays a warning. -### Inputs +### Install only CLIs and startup later +```yml +- name: Install LocalStack CLIs + uses: LocalStack/setup-localstack@v0.2.0 + with: + skip-startup: 'true' + install-awslocal: 'true' + +... + +- name: Start LocalStack + uses: LocalStack/setup-localstack@v0.2.0 + with: + image-tag: 'latest' + env: + LOCALSTACK_API_KEY: ${{ secrets.LOCALSTACK_API_KEY }} +``` + +### Save a state later on in the pipeline +```yml +- name: Save LocalStack State + uses: LocalStack/setup-localstack@v0.2.0 + with: + install-awslocal: 'true' + state-backend: cloud-pods + state-action: save + state-name: my-cloud-pod + env: + LOCALSTACK_API_KEY: ${{ secrets.LOCALSTACK_API_KEY }} +``` +> **NOTE**: The `LOCALSTACK_API_KEY` environment variable is required to be set to save/load LocalStack's state either as a Cloud Pod or as a file artifact. + +### Load an already saved state +```yml +- name: Start LocalStack and Load State + uses: LocalStack/setup-localstack@v0.2.0 + with: + install-awslocal: 'true' + state-backend: cloud-pods + state-action: load + state-name: my-cloud-pod + env: + LOCALSTACK_API_KEY: ${{ secrets.LOCALSTACK_API_KEY }} +``` +> **NOTE**: To load a **local state** from a different GitHub Actions workflow, one must set the `WORKFLOW_ID` environment variable. + +> **NOTE**: The `LOCALSTACK_API_KEY` environment variable is required to be set to **save/load** LocalStack's state either as a Cloud Pod or as a file artifact. + +### Manage App Preview (Ephemeral Instance) +```yml +uses: LocalStack/setup-localstack@$v0.2.0 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + state-backend: ephemeral + state-action: start + # Adding this option prevents Ephemeral Instance to be stopped after the `preview-cmd` run + skip-ephemeral-stop: 'true' + # Optional script/command to run + preview-cmd: deploy.sh + env: + LOCALSTACK_API_KEY: ${{ secrets.LOCALSTACK_API_KEY }} + +... + +with: + uses: LocalStack/setup-localstack@${{ env.GH_ACTION_VERSION }} + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + state-backend: ephemeral + state-action: stop + env: + LOCALSTACK_API_KEY: ${{ secrets.LOCALSTACK_API_KEY }} +``` + +## Inputs | Input | Description | Default | | ------------------ | -------------------------------------------------------------------------------- | -------- | +| `ci-project` | Name of the CI project to track in LocalStack Cloud | | +| `configuration` | Configuration variables to use while starting LocalStack container | `None` | +| `github-token` | Github token used to create PR comments | | | `image-tag` | Tag of the LocalStack Docker image to use | `latest` | +| `include-preview` | Whether to include the created Ephemeral Instance URL in the PR comment | `false` | | `install-awslocal` | Whether to install the `awslocal` CLI into the build environment | `true` | -| `configuration` | Configuration variables to use while starting LocalStack container | `None` | +| `preview-cmd` | Command(s) used to create a Ephemeral Instance of the PR (can use `$AWS_ENDPOINT_URL`) | | +| `skip-ephemeral-stop` | Skip stopping LocalStack Ephemeral Instance | `false` | +| `skip-startup` | Explicitly prevent LocalStack start up, only installs CLI(s). Recommended to manage state later on in the pipeline or start up an ephemeral instance. | `false` | +| `skip-wait` | Skip waiting for LocalStack to start up | `false` | +| `state-action` | Valid values are `load`, `save`, `start`, `stop`, `` (empty, don't manage state). Values `start`/`stop` only usable with app previews. | `` | +| `state-backend` | Either store the state of LocalStack locally, as a Cloud Pod or start an Ephemeral Instance. Valid values are `cloud-pods`, `ephemeral` or `local`. Use this option in unison with `state-action` to control behaviour. | `cloud-pods` | +| `state-name` | Name of the state artifact (without extension) | `false` | | `use-pro` | Whether to use the Pro version of LocalStack (requires API key to be configured) | `false` | -> **NOTE**: The `LOCALSTACK_API_KEY` environment variable is required to be set if `use-pro` is set to `true`. While starting the [localstack-pro](https://hub.docker.com/r/localstack/localstack-pro) image, the DNS startup is skipped with `DNS_ADDRESS=0` configuration variable. It is required to properly start LocalStack in GitHub Actions runner environment. - -### Example workflow - +## Example workflow ```yml name: LocalStack Test on: [ push, pull_request ] @@ -48,12 +134,15 @@ jobs: - uses: actions/checkout@v3 - name: Start LocalStack - uses: HarshCasper/setup-localstack@v0.1.2 + uses: LocalStack/setup-localstack@v0.2.0 with: image-tag: 'latest' install-awslocal: 'true' configuration: DEBUG=1 use-pro: 'true' + state-backend: cloud-pods + state-action: load + state-name: my-cloud-pod env: LOCALSTACK_API_KEY: ${{ secrets.LOCALSTACK_API_KEY }} @@ -61,7 +150,17 @@ jobs: run: | awslocal s3 mb s3://test awslocal s3 ls - echo "Test Execution complete!" + echo "Test Execution complete!" + + - name: Save LocalStack State + uses: LocalStack/setup-localstack@v0.2.0 + with: + state-backend: local + state-action: save + state-name: my-ls-state-artifact + env: + LOCALSTACK_API_KEY: ${{ secrets.LOCALSTACK_API_KEY }} + WORKFLOW_ID: ${{ env.MY_GOLDEN_LS_STATE }} ``` ## License diff --git a/action.yml b/action.yml index 4843538..efdea09 100644 --- a/action.yml +++ b/action.yml @@ -1,6 +1,6 @@ name: 'Setup LocalStack' description: 'Sets up LocalStack CLI in your GitHub Actions workflow.' -author: 'Harsh Mishra' +author: 'LocalStack Team' branding: icon: 'code' @@ -23,31 +23,133 @@ inputs: description: 'Configuration variables to use for LocalStack' required: false default: '' + ci-project: + description: 'Name of the CI project to track in LocalStack Cloud' + required: false + default: '' + github-token: + description: 'Github token used to create PR comments' + required: false + default: '' + preview-cmd: + description: 'Command(s) used to create an Ephemeral Instance of the PR (can use $AWS_ENDPOINT_URL)' + required: false + include-preview: + description: 'Whether to include the created Ephemeral Instance URL in the PR comment' + required: false + skip-startup: + description: | + Explicitly prevent LocalStack start up, only installs CLI(s). + Recommended to manage state later on in the pipeline or start up an ephemeral instance + required: true + default: 'false' + skip-wait: + description: 'Skip wait for LocalStack' + required: false + default: 'false' + skip-ephemeral-stop: + description: 'Skip stopping LocalStack Ephemeral Instance' + required: false + default: 'false' + state-action: + description: | + Manage LocalStack state + Valid values are `load`, `save`, `start`, `stop`, `` (empty, don't manage state) + Values `start`/`stop` only usable with Ephemeral Instances. + required: false + default: '' + state-backend: + description: | + Either store the state of LocalStack locally, as a cloud pod or start up an ephemeral instance. + Valid values are `cloud-pods`, `ephemeral` or `local`. + Use this option in unison with `state-action` to control behaviour. + required: false + default: 'cloud-pods' + state-name: + description: 'Name of the state artifact (without extension)' + required: false runs: using: "composite" steps: - - - run: | - pip install pyopenssl -U - - if [ "$USE_PRO" = true ]; then - docker pull localstack/localstack-pro:"$IMAGE_TAG" - CONFIGURATION="$CONFIGURATION DNS_ADDRESS=0" - else - docker pull localstack/localstack:"$IMAGE_TAG" - fi - - pip install localstack - eval "${CONFIGURATION} localstack start -d" - - localstack wait -t 30 - if [ "$INSTALL_AWSLOCAL" = true ]; then - pip install awscli-local[ver1] - fi + - run: echo "$(ls -d ./../../_actions/LocalStack/setup-localstack/* | grep -v completed)" shell: bash + + - run: echo "GH_ACTION_ROOT=$(ls -d ./../../_actions/LocalStack/setup-localstack/* | grep -v completed)" >> $GITHUB_ENV + shell: bash + + - name: Install tools + uses: jenseng/dynamic-uses@v1 + if: ${{ inputs.skip-startup == 'true' || inputs.state-backend == 'ephemeral' || inputs.state-action == 'save' }} + with: + uses: ${{ env.GH_ACTION_ROOT }}/tools + with: |- + { + "install-awslocal": "${{ inputs.install-awslocal }}", + } + + - name: Start Localstack + uses: jenseng/dynamic-uses@v1 + if: ${{ inputs.skip-startup != 'true' && inputs.state-backend != 'ephemeral' && inputs.state-action != 'save' }} + with: + # now we can dynamically determine sub-action path 🥳 + uses: ${{ env.GH_ACTION_ROOT }}/startup + # the `with` needs to be converted to a valid json string + # keeping in there install-awslocal for backward compatibility + with: |- + { + "image-tag": "${{ inputs.image-tag }}", + "install-awslocal": "${{ inputs.install-awslocal }}", + "use-pro": "${{ inputs.use-pro }}", + "configuration": "${{ inputs.configuration }}", + "ci-project": "${{ inputs.ci-project }}", + "skip-wait": "${{ inputs.skip-wait }}" + } + + - name: Create Ephemeral Instance + if: ${{ inputs.state-action == 'start' && inputs.state-backend == 'ephemeral' }} + uses: jenseng/dynamic-uses@v1 + with: + uses: ${{ env.GH_ACTION_ROOT }}/ephemeral/startup + with: |- + { + "github-token": "${{ inputs.github-token }}", + "preview-cmd": "${{ inputs.preview-cmd }}", + "auto-load-pod": "${{ inputs.state-name }}" + } + + # Use different artifact from current workflow's by passing the workflow's id as WORKFLOW_ID env variable + - name: Manage state + if: ${{ inputs.state-action == 'save' || inputs.state-action == 'load' }} + uses: jenseng/dynamic-uses@v1 + with: + uses: ${{ env.GH_ACTION_ROOT }}/${{ inputs.state-backend }} + with: |- + { + "name": "${{ inputs.state-name }}", + "action": "${{ inputs.state-action }}" + } + + - name: Display Ephemeral Instance URL + if: ${{ inputs.state-action == 'start' && inputs.state-backend == 'ephemeral' && (inputs.include-preview == 'true' || inputs.ci-project != '') }} + uses: jenseng/dynamic-uses@v1 env: - IMAGE_TAG: "${{ inputs.image-tag }}" - INSTALL_AWSLOCAL: "${{ inputs.install-awslocal }}" - USE_PRO: "${{ inputs.use-pro }}" - CONFIGURATION: "${{ inputs.configuration }}" + default-include-preview: ${{ fromJSON('["false","true"]')[github.event_name == 'pull_request'] }} + with: + uses: ${{ env.GH_ACTION_ROOT }}/finish + with: |- + { + "github-token": "${{ inputs.github-token }}", + "ci-project": "${{ inputs.ci-project }}", + "include-preview": "${{ inputs.include-preview != '' && inputs.include-preview || env.include-preview }}" + } + + - name: Stop Ephemeral Instance + if: ${{ !inputs.skip-ephemeral-stop && inputs.state-action == 'stop' && inputs.state-backend == 'ephemeral' }} + uses: jenseng/dynamic-uses@v1 + with: + uses: ${{ env.GH_ACTION_ROOT }}/ephemeral/shutdown + with: |- + { + "name": "${{ inputs.github-token }}", + } \ No newline at end of file diff --git a/cloud-pods/action.yml b/cloud-pods/action.yml new file mode 100644 index 0000000..8058c1c --- /dev/null +++ b/cloud-pods/action.yml @@ -0,0 +1,31 @@ +name: 'Save/Load a LocalStack Cloud Pod' + +inputs: + name: + description: 'Name of the Cloud Pod' + required: true + default: 'cloud-pod' + action: + description: 'Action to perform (save or load)' + required: true + default: 'save' + +runs: + using: "composite" + steps: + - + run: | + if [ "$ACTION" = "save" ]; then + echo "Saving Cloud Pod $NAME" + localstack pod save $NAME + elif [ "$ACTION" = "load" ]; then + echo "Loading Cloud Pod $NAME" + localstack pod load --yes $NAME + else + echo "Invalid action: $ACTION" + exit 1 + fi + shell: bash + env: + NAME: "${{ inputs.name }}" + ACTION: "${{ inputs.action }}" diff --git a/ephemeral/shutdown/action.yml b/ephemeral/shutdown/action.yml new file mode 100644 index 0000000..664e7f7 --- /dev/null +++ b/ephemeral/shutdown/action.yml @@ -0,0 +1,51 @@ +name: Shutdown Ephemeral Instance + +inputs: + localstack-api-key: + description: 'LocalStack API key used to access the platform api' + required: true + github-token: + description: 'Github token used to create PR comments' + required: true + + +runs: + using: composite + steps: + - name: Download PR artifact + uses: actions/download-artifact@v3 + with: + name: pr + + - name: Load the PR ID + id: pr + shell: bash + run: echo "pr_id=$(> $GITHUB_OUTPUT + + - name: Shutdown ephemeral instance + shell: bash + run: | + prId=$( + body-include: '' + number: ${{ steps.pr.outputs.pr_id }} diff --git a/ephemeral/startup/action.yml b/ephemeral/startup/action.yml new file mode 100644 index 0000000..a3c0981 --- /dev/null +++ b/ephemeral/startup/action.yml @@ -0,0 +1,73 @@ +name: Create PR Preview + +inputs: + github-token: + description: 'Github token used to create PR comments' + required: true + localstack-api-key: + description: 'LocalStack API key used to create the preview environment' + required: false + preview-cmd: + description: 'Command(s) used to create a preview of the PR (can use $AWS_ENDPOINT_URL)' + required: false + default: '' + auto-load-pod: + description: 'The pod to load on startup of LocalStack, the env var AUTO_LOAD_POD' + required: false + default: '' + +runs: + using: composite + steps: + - run: echo "GH_ACTION_ROOT=$(ls -d ./../../_actions/LocalStack/setup-localstack/* | grep -v completed)" >> $GITHUB_ENV + shell: bash + + - name: Initial PR comment + if: inputs.github-token + uses: jenseng/dynamic-uses@v1 + with: + uses: ${{ env.GH_ACTION_ROOT }}/prepare + with: |- + { + "github-token": "${{ inputs.github-token }}" + } + + - name: Download PR artifact + uses: actions/download-artifact@v3 + with: + name: pr + + - name: Create preview environment + shell: bash + run: | + prId=$( ./ls-preview-url.txt + echo "LS_PREVIEW_URL=$endpointUrl" >> $GITHUB_ENV + echo "AWS_ENDPOINT_URL=$endpointUrl" >> $GITHUB_ENV + + - name: Upload preview instance URL + uses: actions/upload-artifact@v3 + with: + name: pr + path: ./ls-preview-url.txt + + - name: Run preview deployment + if: ${{ inputs.preview-cmd != '' }} + shell: bash + run: + ${{ inputs.preview-cmd }} diff --git a/finish/action.yml b/finish/action.yml new file mode 100644 index 0000000..eb8c95f --- /dev/null +++ b/finish/action.yml @@ -0,0 +1,52 @@ +name: Finish CI Build + +inputs: + github-token: + description: 'Github token used to create PR comments' + required: true + ci-project: + description: 'Name of the CI project tracked in LocalStack Cloud' + required: false + include-preview: + description: 'Whether to include the created Ephemeral Instance URL in the PR comment' + required: false + preview-url: + description: 'The Ephmeral Instance URL to include in the PR comment' + required: false + +runs: + using: composite + steps: + - name: Download PR artifact + uses: dawidd6/action-download-artifact@v2 + with: + workflow: ${{ github.event.workflow_run.workflow_id }} + name: pr + + - name: Load the PR ID + id: pr + shell: bash + run: echo "pr_id=$(> $GITHUB_OUTPUT + + - name: Load the Ephemeral Instance URL + shell: bash + if: inputs.include-preview + run: | + if [[ -n "${{ inputs.preview-url }}" ]]; then + echo "LS_PREVIEW_URL=${{ inputs.preview-url }}" >> $GITHUB_ENV + elif [[ -e ls-preview-url.txt ]]; then + echo "LS_PREVIEW_URL=$(> $GITHUB_ENV + else + echo "LS_PREVIEW_URL=Unable to determine preview URL" >> $GITHUB_ENV + fi + + - name: Update status comment + uses: actions-cool/maintain-one-comment@v3.1.1 + with: + token: ${{ inputs.github-token }} + body: | + ${{ inputs.ci-project && format('{0}{1}', '🚀 LocalStack Stack Insights and Cloud Pod state for this CI run: https://app.localstack.cloud/ci/', inputs.ci-project) }} + ${{ inputs.include-preview && format('{0}{1}', '🚀 Preview for this PR: ', env.LS_PREVIEW_URL) }} + + body-include: '' + number: ${{ steps.pr.outputs.pr_id }} diff --git a/local/action.yml b/local/action.yml new file mode 100644 index 0000000..9f56139 --- /dev/null +++ b/local/action.yml @@ -0,0 +1,46 @@ +name: 'Save/Load LocalStack state' + +inputs: + name: + description: 'Name of the artifact' + required: true + default: 'ls-state' + action: + description: 'Action to perform (save or load)' + required: true + default: 'save' + +runs: + using: "composite" + steps: + - name: Download PR artifact + uses: dawidd6/action-download-artifact@v2 + if: ${{ inputs.action == 'load' }} + env: + workflow_id: ${{ env.WORKFLOW_ID == '' && github.event.workflow_run.workflow_id || env.WORKFLOW_ID }} + with: + workflow: + name: ${{ inputs.name }} + + - run: | + if [ "$ACTION" = "save" ]; then + echo "Saving State $NAME" + localstack state export ${NAME}.zip + elif [ "$ACTION" = "load" ]; then + echo "Loading State $NAME" + localstack state import ${NAME}.zip + else + echo "Invalid action: $ACTION" + exit 1 + fi + shell: bash + env: + NAME: "${{ inputs.name }}" + ACTION: "${{ inputs.action }}" + + - name: Upload LocalStack State + uses: actions/upload-artifact@v3 + if: ${{ inputs.action == 'save' }} + with: + name: ${{ inputs.name }} + path: ./${{ inputs.name }}.zip diff --git a/prepare/action.yml b/prepare/action.yml new file mode 100644 index 0000000..d1276d1 --- /dev/null +++ b/prepare/action.yml @@ -0,0 +1,31 @@ +name: Start CI Build + +inputs: + github-token: + description: 'Github token used to create PR comments' + required: true + ci-project: + description: 'Name of the CI project to track in LocalStack Cloud' + required: false + +runs: + using: composite + steps: + - name: Save PR number + shell: bash + run: echo ${{ github.event.number }} > ./pr-id.txt + + - name: Upload PR number + uses: actions/upload-artifact@v3 + with: + name: pr + path: ./pr-id.txt + + - name: Create initial PR comment + uses: actions-cool/maintain-one-comment@v3.1.1 + with: + token: ${{ inputs.github-token }} + body: | + ⚡️ Running CI build with LocalStack ... + + body-include: '' diff --git a/startup/action.yml b/startup/action.yml new file mode 100644 index 0000000..bd8b760 --- /dev/null +++ b/startup/action.yml @@ -0,0 +1,78 @@ +name: 'Start up Localstack' + +inputs: + image-tag: + description: 'Tag of the LocalStack Docker image to use' + required: true + default: 'latest' + install-awslocal: + description: 'Whether to install the `awslocal` CLI into the environment' + required: true + default: 'true' + use-pro: + description: 'Whether to use LocalStack Pro (requires a valid API key)' + required: false + default: 'false' + configuration: + description: 'Configuration variables to use for LocalStack' + required: false + default: '' + ci-project: + description: 'Name of the CI project to track in LocalStack Cloud' + required: false + default: '' + skip-wait: + description: 'Skip wait for LocalStack' + required: false + default: 'false' + +runs: + using: "composite" + steps: + # # NOTE: Thinking about this if we need it + # - name: Initial PR comment + # # TODO: potentially replace with Action version number over time + # uses: LocalStack/setup-localstack/prepare@main + # if: inputs.ci-project && inputs.github-token + # with: + # github-token: ${{ inputs.github-token }} + # ci-project: ${{ inputs.ci-project }} + - run: echo "GH_ACTION_ROOT=$(ls -d ./../../_actions/LocalStack/setup-localstack/* | grep -v completed)" >> $GITHUB_ENV + shell: bash + + - name: Install tools + uses: jenseng/dynamic-uses@v1 + with: + uses: ${{ env.GH_ACTION_ROOT }}/tools + with: |- + { + "install-awslocal": "${{ inputs.install-awslocal }}", + } + + - name: Start LocalStack + run: | + if [ "$USE_PRO" = true ]; then + if [ "x$LOCALSTACK_AUTH_TOKEN" = "x" -o "x$LOCALSTACK_API_KEY" = "x" ]; then + echo "WARNING: LocalStack API key not detected, please verify your configuration..." + fi + docker pull localstack/localstack-pro:"$IMAGE_TAG" & + CONFIGURATION="$CONFIGURATION DNS_ADDRESS=127.0.0.1" + else + docker pull localstack/localstack:"$IMAGE_TAG" & + fi + + export CI_PROJECT=${{ inputs.ci-project }} + eval "${CONFIGURATION} localstack start -d" + + if [ "$SKIP_WAIT" = false ]; then + localstack wait -t ${LS_WAIT_TIMEOUT:-30} # Let users configure the timeout via env variable + fi + + shell: bash + env: + IMAGE_TAG: ${{ inputs.image-tag }} + INSTALL_AWSLOCAL: ${{ inputs.install-awslocal }} + USE_PRO: ${{ inputs.use-pro }} + CONFIGURATION: ${{ inputs.configuration }} + SKIP_WAIT: ${{ inputs.skip-wait }} + diff --git a/tools/action.yml b/tools/action.yml new file mode 100644 index 0000000..65b59fd --- /dev/null +++ b/tools/action.yml @@ -0,0 +1,22 @@ +name: 'Install Localstack tools' + +inputs: + install-awslocal: + description: 'Whether to install the `awslocal` CLI into the environment' + required: true + default: 'true' + +runs: + using: "composite" + steps: + - name: Start LocalStack + run: | + which localstack > /dev/null || pip install localstack + if [ "$INSTALL_AWSLOCAL" = true ]; then + which awslocal > /dev/null || pip install awscli-local[ver1] + fi + + shell: bash + env: + INSTALL_AWSLOCAL: "${{ inputs.install-awslocal }}" +