mirror of
https://code.forgejo.org/forgejo/runner.git
synced 2025-10-10 19:32:04 +00:00
feat: validate --directory alternative to --repository to not clone (#1008)
Resolves forgejo/forgejo-actions-feature-requests#51 --- Note to reviewers: while working on fixing the exit status of the validate command, a border case was discovered when using `--clonedir . --repository .` by which it will not find an `action.yml` file at the root of the directory. It will be easier to fix and test using a `--directory` option designed to use a pre-existing directory instead because it is not a border case but the most common case really. <!--start release-notes-assistant--> <!--URL:https://code.forgejo.org/forgejo/runner--> - features - [PR](https://code.forgejo.org/forgejo/runner/pulls/1008): <!--number 1008 --><!--line 0 --><!--description ZmVhdDogdmFsaWRhdGUgLS1kaXJlY3RvcnkgYWx0ZXJuYXRpdmUgdG8gLS1yZXBvc2l0b3J5IHRvIG5vdCBjbG9uZQ==-->feat: validate --directory alternative to --repository to not clone<!--description--> <!--end release-notes-assistant--> Reviewed-on: https://code.forgejo.org/forgejo/runner/pulls/1008 Reviewed-by: Mathieu Fenniak <mfenniak@noreply.code.forgejo.org> Co-authored-by: Earl Warren <contact@earl-warren.org> Co-committed-by: Earl Warren <contact@earl-warren.org>
This commit is contained in:
parent
aaf9dea44a
commit
89f37985bd
12 changed files with 293 additions and 6 deletions
6
internal/app/cmd/testdata/validate/bad-directory/.forgejo/workflows/workflow1.yml
vendored
Normal file
6
internal/app/cmd/testdata/validate/bad-directory/.forgejo/workflows/workflow1.yml
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
on: [push]
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
ruins-on: docker
|
||||||
|
steps:
|
||||||
|
- run: echo All good!
|
67
internal/app/cmd/testdata/validate/bad-directory/action.yml
vendored
Normal file
67
internal/app/cmd/testdata/validate/bad-directory/action.yml
vendored
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
name: 'Forgejo release download and upload'
|
||||||
|
author: 'Forgejo authors'
|
||||||
|
description: |
|
||||||
|
Upload or download the assets of a release to a Forgejo instance.
|
||||||
|
inputs:
|
||||||
|
badinput: scalarinsteadofmap
|
||||||
|
url:
|
||||||
|
description: 'URL of the Forgejo instance'
|
||||||
|
default: '${{ env.FORGEJO_SERVER_URL }}'
|
||||||
|
repo:
|
||||||
|
description: 'owner/project relative to the URL'
|
||||||
|
default: '${{ forge.repository }}'
|
||||||
|
tag:
|
||||||
|
description: 'Tag of the release'
|
||||||
|
default: '${{ forge.ref_name }}'
|
||||||
|
title:
|
||||||
|
description: 'Title of the release (defaults to tag)'
|
||||||
|
sha:
|
||||||
|
description: 'SHA of the release'
|
||||||
|
default: '${{ forge.sha }}'
|
||||||
|
token:
|
||||||
|
description: 'Forgejo application token'
|
||||||
|
default: '${{ forge.token }}'
|
||||||
|
release-dir:
|
||||||
|
description: 'Directory in whichs release assets are uploaded or downloaded'
|
||||||
|
required: true
|
||||||
|
release-notes:
|
||||||
|
description: 'Release notes'
|
||||||
|
direction:
|
||||||
|
description: 'Can either be `download` or `upload`'
|
||||||
|
required: true
|
||||||
|
gpg-private-key:
|
||||||
|
description: 'GPG Private Key to sign the release artifacts'
|
||||||
|
gpg-passphrase:
|
||||||
|
description: 'Passphrase of the GPG Private Key'
|
||||||
|
download-retry:
|
||||||
|
description: 'Number of times to retry if the release is not ready (default 1)'
|
||||||
|
download-latest:
|
||||||
|
description: 'Download the latest release'
|
||||||
|
default: false
|
||||||
|
verbose:
|
||||||
|
description: 'Increase the verbosity level'
|
||||||
|
default: false
|
||||||
|
override:
|
||||||
|
description: 'Override an existing release by the same `{tag}`'
|
||||||
|
default: false
|
||||||
|
prerelease:
|
||||||
|
description: 'Mark Release as Pre-Release'
|
||||||
|
default: false
|
||||||
|
release-notes-assistant:
|
||||||
|
description: 'Generate release notes with Release Notes Assistant'
|
||||||
|
default: false
|
||||||
|
hide-archive-link:
|
||||||
|
description: 'Hide the archive links'
|
||||||
|
default: false
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- if: ${{ inputs.release-notes-assistant }}
|
||||||
|
uses: https://data.forgejo.org/actions/cache@v4
|
||||||
|
with:
|
||||||
|
key: rna-${{ inputs.repo }}
|
||||||
|
path: ${{ forge.action_path }}/rna
|
||||||
|
|
||||||
|
- run: echo "${{ forge.action_path }}" >> $FORGEJO_PATH
|
||||||
|
shell: bash
|
6
internal/app/cmd/testdata/validate/good-directory/.forgejo/workflows/action.yml
vendored
Normal file
6
internal/app/cmd/testdata/validate/good-directory/.forgejo/workflows/action.yml
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
on: [push]
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: docker
|
||||||
|
steps:
|
||||||
|
- run: echo All good!
|
6
internal/app/cmd/testdata/validate/good-directory/.forgejo/workflows/workflow1.yml
vendored
Normal file
6
internal/app/cmd/testdata/validate/good-directory/.forgejo/workflows/workflow1.yml
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
on: [push]
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: docker
|
||||||
|
steps:
|
||||||
|
- run: echo All good!
|
6
internal/app/cmd/testdata/validate/good-directory/.forgejo/workflows/workflow2.yaml
vendored
Normal file
6
internal/app/cmd/testdata/validate/good-directory/.forgejo/workflows/workflow2.yaml
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
on: [push]
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: docker
|
||||||
|
steps:
|
||||||
|
- run: echo All good!
|
6
internal/app/cmd/testdata/validate/good-directory/.gitea/workflows/bad.yml
vendored
Normal file
6
internal/app/cmd/testdata/validate/good-directory/.gitea/workflows/bad.yml
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
on: [push]
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
ruins-on: docker
|
||||||
|
steps:
|
||||||
|
- run: echo All good!
|
6
internal/app/cmd/testdata/validate/good-directory/.github/workflows/bad.yml
vendored
Normal file
6
internal/app/cmd/testdata/validate/good-directory/.github/workflows/bad.yml
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
on: [push]
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
ruins-on: docker
|
||||||
|
steps:
|
||||||
|
- run: echo All good!
|
67
internal/app/cmd/testdata/validate/good-directory/action.yml
vendored
Normal file
67
internal/app/cmd/testdata/validate/good-directory/action.yml
vendored
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
name: 'Forgejo release download and upload'
|
||||||
|
author: 'Forgejo authors'
|
||||||
|
description: |
|
||||||
|
Upload or download the assets of a release to a Forgejo instance.
|
||||||
|
inputs:
|
||||||
|
url:
|
||||||
|
description: 'URL of the Forgejo instance'
|
||||||
|
default: '${{ env.FORGEJO_SERVER_URL }}'
|
||||||
|
repo:
|
||||||
|
description: 'owner/project relative to the URL'
|
||||||
|
default: '${{ forge.repository }}'
|
||||||
|
tag:
|
||||||
|
description: 'Tag of the release'
|
||||||
|
default: '${{ forge.ref_name }}'
|
||||||
|
title:
|
||||||
|
description: 'Title of the release (defaults to tag)'
|
||||||
|
sha:
|
||||||
|
description: 'SHA of the release'
|
||||||
|
default: '${{ forge.sha }}'
|
||||||
|
token:
|
||||||
|
description: 'Forgejo application token'
|
||||||
|
default: '${{ forge.token }}'
|
||||||
|
release-dir:
|
||||||
|
description: 'Directory in whichs release assets are uploaded or downloaded'
|
||||||
|
required: true
|
||||||
|
release-notes:
|
||||||
|
description: 'Release notes'
|
||||||
|
direction:
|
||||||
|
description: 'Can either be `download` or `upload`'
|
||||||
|
required: true
|
||||||
|
gpg-private-key:
|
||||||
|
description: 'GPG Private Key to sign the release artifacts'
|
||||||
|
gpg-passphrase:
|
||||||
|
description: 'Passphrase of the GPG Private Key'
|
||||||
|
download-retry:
|
||||||
|
description: 'Number of times to retry if the release is not ready (default 1)'
|
||||||
|
download-latest:
|
||||||
|
description: 'Download the latest release'
|
||||||
|
default: false
|
||||||
|
verbose:
|
||||||
|
description: 'Increase the verbosity level'
|
||||||
|
default: false
|
||||||
|
override:
|
||||||
|
description: 'Override an existing release by the same `{tag}`'
|
||||||
|
default: false
|
||||||
|
prerelease:
|
||||||
|
description: 'Mark Release as Pre-Release'
|
||||||
|
default: false
|
||||||
|
release-notes-assistant:
|
||||||
|
description: 'Generate release notes with Release Notes Assistant'
|
||||||
|
default: false
|
||||||
|
hide-archive-link:
|
||||||
|
description: 'Hide the archive links'
|
||||||
|
default: false
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- if: ${{ inputs.release-notes-assistant }}
|
||||||
|
uses: https://data.forgejo.org/actions/cache@v4
|
||||||
|
with:
|
||||||
|
key: rna-${{ inputs.repo }}
|
||||||
|
path: ${{ forge.action_path }}/rna
|
||||||
|
|
||||||
|
- run: echo "${{ forge.action_path }}" >> $FORGEJO_PATH
|
||||||
|
shell: bash
|
67
internal/app/cmd/testdata/validate/good-directory/subaction/action.yaml
vendored
Normal file
67
internal/app/cmd/testdata/validate/good-directory/subaction/action.yaml
vendored
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
name: 'Forgejo release download and upload'
|
||||||
|
author: 'Forgejo authors'
|
||||||
|
description: |
|
||||||
|
Upload or download the assets of a release to a Forgejo instance.
|
||||||
|
inputs:
|
||||||
|
url:
|
||||||
|
description: 'URL of the Forgejo instance'
|
||||||
|
default: '${{ env.FORGEJO_SERVER_URL }}'
|
||||||
|
repo:
|
||||||
|
description: 'owner/project relative to the URL'
|
||||||
|
default: '${{ forge.repository }}'
|
||||||
|
tag:
|
||||||
|
description: 'Tag of the release'
|
||||||
|
default: '${{ forge.ref_name }}'
|
||||||
|
title:
|
||||||
|
description: 'Title of the release (defaults to tag)'
|
||||||
|
sha:
|
||||||
|
description: 'SHA of the release'
|
||||||
|
default: '${{ forge.sha }}'
|
||||||
|
token:
|
||||||
|
description: 'Forgejo application token'
|
||||||
|
default: '${{ forge.token }}'
|
||||||
|
release-dir:
|
||||||
|
description: 'Directory in whichs release assets are uploaded or downloaded'
|
||||||
|
required: true
|
||||||
|
release-notes:
|
||||||
|
description: 'Release notes'
|
||||||
|
direction:
|
||||||
|
description: 'Can either be `download` or `upload`'
|
||||||
|
required: true
|
||||||
|
gpg-private-key:
|
||||||
|
description: 'GPG Private Key to sign the release artifacts'
|
||||||
|
gpg-passphrase:
|
||||||
|
description: 'Passphrase of the GPG Private Key'
|
||||||
|
download-retry:
|
||||||
|
description: 'Number of times to retry if the release is not ready (default 1)'
|
||||||
|
download-latest:
|
||||||
|
description: 'Download the latest release'
|
||||||
|
default: false
|
||||||
|
verbose:
|
||||||
|
description: 'Increase the verbosity level'
|
||||||
|
default: false
|
||||||
|
override:
|
||||||
|
description: 'Override an existing release by the same `{tag}`'
|
||||||
|
default: false
|
||||||
|
prerelease:
|
||||||
|
description: 'Mark Release as Pre-Release'
|
||||||
|
default: false
|
||||||
|
release-notes-assistant:
|
||||||
|
description: 'Generate release notes with Release Notes Assistant'
|
||||||
|
default: false
|
||||||
|
hide-archive-link:
|
||||||
|
description: 'Hide the archive links'
|
||||||
|
default: false
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- if: ${{ inputs.release-notes-assistant }}
|
||||||
|
uses: https://data.forgejo.org/actions/cache@v4
|
||||||
|
with:
|
||||||
|
key: rna-${{ inputs.repo }}
|
||||||
|
path: ${{ forge.action_path }}/rna
|
||||||
|
|
||||||
|
- run: echo "${{ forge.action_path }}" >> $FORGEJO_PATH
|
||||||
|
shell: bash
|
|
@ -35,6 +35,10 @@ git clone --bare $tmpdir/good good-repository
|
||||||
rm -fr good-repository/hooks
|
rm -fr good-repository/hooks
|
||||||
touch good-repository/refs/placeholder
|
touch good-repository/refs/placeholder
|
||||||
|
|
||||||
|
rm -fr good-directory
|
||||||
|
git clone $tmpdir/good good-directory
|
||||||
|
rm -fr good-directory/.git
|
||||||
|
|
||||||
# bad
|
# bad
|
||||||
|
|
||||||
mkdir $tmpdir/bad
|
mkdir $tmpdir/bad
|
||||||
|
@ -54,3 +58,7 @@ rm -fr bad-repository
|
||||||
git clone --bare $tmpdir/bad bad-repository
|
git clone --bare $tmpdir/bad bad-repository
|
||||||
rm -fr bad-repository/hooks
|
rm -fr bad-repository/hooks
|
||||||
touch bad-repository/refs/placeholder
|
touch bad-repository/refs/placeholder
|
||||||
|
|
||||||
|
rm -fr bad-directory
|
||||||
|
git clone $tmpdir/bad bad-directory
|
||||||
|
rm -fr bad-directory/.git
|
||||||
|
|
|
@ -23,6 +23,7 @@ type validateArgs struct {
|
||||||
path string
|
path string
|
||||||
repository string
|
repository string
|
||||||
clonedir string
|
clonedir string
|
||||||
|
directory string
|
||||||
workflow bool
|
workflow bool
|
||||||
action bool
|
action bool
|
||||||
}
|
}
|
||||||
|
@ -145,8 +146,16 @@ func validateRepository(validateArgs *validateArgs) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func processDirectory(validateArgs *validateArgs) {
|
||||||
|
if len(validateArgs.directory) > 0 {
|
||||||
|
validateArgs.repository = validateArgs.directory
|
||||||
|
validateArgs.clonedir = validateArgs.directory
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func runValidate(_ context.Context, validateArgs *validateArgs) func(cmd *cobra.Command, args []string) error {
|
func runValidate(_ context.Context, validateArgs *validateArgs) func(cmd *cobra.Command, args []string) error {
|
||||||
return func(cmd *cobra.Command, args []string) error {
|
return func(cmd *cobra.Command, args []string) error {
|
||||||
|
processDirectory(validateArgs)
|
||||||
if len(validateArgs.path) > 0 {
|
if len(validateArgs.path) > 0 {
|
||||||
return validatePath(validateArgs)
|
return validatePath(validateArgs)
|
||||||
} else if len(validateArgs.repository) > 0 {
|
} else if len(validateArgs.repository) > 0 {
|
||||||
|
@ -168,9 +177,15 @@ Validate workflows or actions with a schema verifying they are conformant.
|
||||||
The --path argument is a filename that will be validated as a workflow
|
The --path argument is a filename that will be validated as a workflow
|
||||||
(if the --workflow flag is set) or as an action (if the --action flag is set).
|
(if the --workflow flag is set) or as an action (if the --action flag is set).
|
||||||
|
|
||||||
The --repository argument is a URL to a Git repository. It will be
|
The --repository argument is a URL to a Git repository that contains
|
||||||
cloned (in the --clonedir directory or a temporary location removed
|
workflows or actions. It will be cloned (in the --clonedir directory
|
||||||
when the validation completes). The following files will be validated:
|
or a temporary location removed when the validation completes).
|
||||||
|
|
||||||
|
The --directory argument is the path a repository to be explored for
|
||||||
|
files to validate.
|
||||||
|
|
||||||
|
The following files will be validated when exploring the clone of a repository
|
||||||
|
(--repository) or a directory (--directory):
|
||||||
|
|
||||||
- All .forgejo/workflows/*.{yml,yaml} files as workflows
|
- All .forgejo/workflows/*.{yml,yaml} files as workflows
|
||||||
- All **/action.{yml,yaml} files as actions
|
- All **/action.{yml,yaml} files as actions
|
||||||
|
@ -185,9 +200,11 @@ when the validation completes). The following files will be validated:
|
||||||
|
|
||||||
validateCmd.Flags().StringVar(&validateArgs.clonedir, "clonedir", "", "directory in which the repository will be cloned")
|
validateCmd.Flags().StringVar(&validateArgs.clonedir, "clonedir", "", "directory in which the repository will be cloned")
|
||||||
validateCmd.Flags().StringVar(&validateArgs.repository, "repository", "", "URL to a repository to validate")
|
validateCmd.Flags().StringVar(&validateArgs.repository, "repository", "", "URL to a repository to validate")
|
||||||
|
validateCmd.Flags().StringVar(&validateArgs.directory, "directory", "", "directory to a repository to validate")
|
||||||
validateCmd.Flags().StringVar(&validateArgs.path, "path", "", "path to the file")
|
validateCmd.Flags().StringVar(&validateArgs.path, "path", "", "path to the file")
|
||||||
validateCmd.MarkFlagsOneRequired("repository", "path")
|
validateCmd.MarkFlagsOneRequired("repository", "path", "directory")
|
||||||
validateCmd.MarkFlagsMutuallyExclusive("repository", "path")
|
validateCmd.MarkFlagsMutuallyExclusive("repository", "path", "directory")
|
||||||
|
validateCmd.MarkFlagsMutuallyExclusive("directory", "clonedir")
|
||||||
|
|
||||||
return validateCmd
|
return validateCmd
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,10 +27,20 @@ func Test_validateCmd(t *testing.T) {
|
||||||
message: "one of --workflow or --action must be set",
|
message: "one of --workflow or --action must be set",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "MutuallyExclusive",
|
name: "MutuallyExclusiveActionWorkflow",
|
||||||
args: []string{"--action", "--workflow", "--path", "/tmp"},
|
args: []string{"--action", "--workflow", "--path", "/tmp"},
|
||||||
message: "[action workflow] were all set",
|
message: "[action workflow] were all set",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "MutuallyExclusiveRepositoryDirectory",
|
||||||
|
args: []string{"--repository", "example.com", "--directory", "."},
|
||||||
|
message: "[directory repository] were all set",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "MutuallyExclusiveClonedirDirectory",
|
||||||
|
args: []string{"--clonedir", ".", "--directory", "."},
|
||||||
|
message: "[clonedir directory] were all set",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "PathActionOK",
|
name: "PathActionOK",
|
||||||
args: []string{"--action", "--path", "testdata/validate/good-action.yml"},
|
args: []string{"--action", "--path", "testdata/validate/good-action.yml"},
|
||||||
|
@ -51,6 +61,21 @@ func Test_validateCmd(t *testing.T) {
|
||||||
args: []string{"--workflow", "--path", "testdata/validate/bad-workflow.yml"},
|
args: []string{"--workflow", "--path", "testdata/validate/bad-workflow.yml"},
|
||||||
stdOut: "Unknown Property ruins-on",
|
stdOut: "Unknown Property ruins-on",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "DirectoryOK",
|
||||||
|
args: []string{"--directory", "testdata/validate/good-directory"},
|
||||||
|
stdOut: "action.yml action schema validation OK\nsubaction/action.yaml action schema validation OK\n.forgejo/workflows/action.yml workflow schema validation OK\n.forgejo/workflows/workflow1.yml workflow schema validation OK\n.forgejo/workflows/workflow2.yaml workflow schema validation OK",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "DirectoryActionNOK",
|
||||||
|
args: []string{"--directory", "testdata/validate/bad-directory"},
|
||||||
|
stdOut: "action.yml action schema validation failed",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "DirectoryWorkflowNOK",
|
||||||
|
args: []string{"--directory", "testdata/validate/bad-directory"},
|
||||||
|
stdOut: ".forgejo/workflows/workflow1.yml workflow schema validation failed",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "RepositoryOK",
|
name: "RepositoryOK",
|
||||||
args: []string{"--repository", "testdata/validate/good-repository"},
|
args: []string{"--repository", "testdata/validate/good-repository"},
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue