diff --git a/.gitea/workflows/checks.yml b/.gitea/workflows/checks.yml new file mode 100644 index 00000000..11a4d0b0 --- /dev/null +++ b/.gitea/workflows/checks.yml @@ -0,0 +1,144 @@ +name: checks +on: [pull_request, workflow_dispatch] + +concurrency: + cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.ref }} + +env: + ACT_OWNER: ${{ github.repository_owner }} + ACT_REPOSITORY: ${{ github.repository }} + CGO_ENABLED: 0 + NO_QEMU: 1 + NO_EXTERNAL_IP: 1 + DOOD: 1 + +jobs: + lint: + name: lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 0 + - uses: actions/setup-go@v6 + with: + go-version-file: go.mod + check-latest: true + - uses: golangci/golangci-lint-action@v8.0.0 + with: + version: v2.1.6 + - uses: megalinter/megalinter/flavors/go@v9.1.0 + env: + DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VALIDATE_ALL_CODEBASE: false + GITHUB_STATUS_REPORTER: ${{ !env.ACT }} + GITHUB_COMMENT_REPORTER: ${{ !env.ACT }} + + test-linux: + name: test-linux + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 2 + - name: Set up QEMU + if: '!env.NO_QEMU' + uses: docker/setup-qemu-action@v3 + - uses: actions/setup-go@v6 + with: + go-version-file: go.mod + check-latest: true + - uses: actions/cache@v4 + if: ${{ !env.ACT }} + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + - name: Install gotestfmt + run: go install github.com/gotesttools/gotestfmt/v2/cmd/gotestfmt@v2.5.0 + # Regressions by Gitea Actions CI Migration + # GITHUB_REPOSITORY contains the server url + # ACTIONS_RUNTIME_URL provided to every step, act does not override + - name: Run Tests + run: | + unset ACTIONS_RUNTIME_URL + unset ACTIONS_RESULTS_URL + unset ACTIONS_RUNTIME_TOKEN + export GITHUB_REPOSITORY="${GITHUB_REPOSITORY#${SERVER_URL%/}/}" + export ACT_REPOSITORY="${GITHUB_REPOSITORY#${SERVER_URL%/}/}" + export ACT_OWNER="${ACT_OWNER#${SERVER_URL%/}/}" + env + go test -json -v -cover -coverpkg=./... -coverprofile=coverage.txt -covermode=atomic -timeout 20m ./... | gotestfmt -hide successful-packages,empty-packages 2>&1 + env: + SERVER_URL: ${{ github.server_url }} + - name: Run act from cli + run: go run main.go -P ubuntu-latest=node:16-buster-slim -C ./pkg/runner/testdata/ -W ./basic/push.yml + - name: Run act from cli without docker support + run: go run -tags WITHOUT_DOCKER main.go -P ubuntu-latest=-self-hosted -C ./pkg/runner/testdata/ -W ./local-action-js/push.yml + + snapshot: + name: snapshot + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-go@v6 + with: + go-version-file: go.mod + check-latest: true + - uses: actions/cache@v4 + if: ${{ !env.ACT }} + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + - name: GoReleaser + id: goreleaser + uses: goreleaser/goreleaser-action@v6 + with: + version: v2 + args: release --snapshot --clean + - name: Setup Node + continue-on-error: true + uses: actions/setup-node@v6 + with: + node-version: 20 + - name: Install @actions/artifact@2.1.0 + continue-on-error: true + run: npm install @actions/artifact@2.1.0 + - name: Upload All + uses: actions/github-script@v8 + continue-on-error: true + with: + script: | + // We do not use features depending on GITHUB_API_URL so we can hardcode it to avoid the GHES no support error + process.env["GITHUB_SERVER_URL"] = "https://github.com"; + const {DefaultArtifactClient} = require('@actions/artifact'); + const aartifact = new DefaultArtifactClient(); + var artifacts = JSON.parse(process.env.ARTIFACTS); + for(var artifact of artifacts) { + if(artifact.type === "Binary") { + const {id, size} = await aartifact.uploadArtifact( + // name of the artifact + `${artifact.name}-${artifact.target}`, + // files to include (supports absolute and relative paths) + [artifact.path], + process.cwd(), + { + // optional: how long to retain the artifact + // if unspecified, defaults to repository/org retention settings (the limit of this value) + retentionDays: 10 + } + ); + console.log(`Created artifact with id: ${id} (bytes: ${size}`); + } + } + env: + ARTIFACTS: ${{ steps.goreleaser.outputs.artifacts }} + - name: Chocolatey + uses: ./.github/actions/choco + with: + version: v0.0.0-pr diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml new file mode 100644 index 00000000..e6ea61d9 --- /dev/null +++ b/.gitea/workflows/release.yml @@ -0,0 +1,72 @@ +name: release +on: + push: + tags: + - v* + +jobs: + release: + # TODO use environment to scope secrets + name: release + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 0 + - uses: actions/setup-go@v6 + with: + go-version-file: go.mod + check-latest: true + - uses: actions/cache@v4 + if: ${{ !env.ACT }} + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + - name: GoReleaser + uses: goreleaser/goreleaser-action@v6 + with: + version: latest + args: release --clean + env: + GITHUB_TOKEN: ${{ secrets.GORELEASER_GITHUB_TOKEN || github.token }} + - name: Winget + uses: vedantmgoyal2009/winget-releaser@v2 + with: + identifier: nektos.act + installers-regex: '_Windows_\w+\.zip$' + token: ${{ secrets.WINGET_TOKEN }} + if: env.ENABLED + env: + ENABLED: ${{ secrets.WINGET_TOKEN && '1' || '' }} + - name: Chocolatey + uses: ./.github/actions/choco + with: + version: ${{ github.ref }} + apiKey: ${{ secrets.CHOCO_APIKEY }} + push: true + if: env.ENABLED + env: + ENABLED: ${{ secrets.CHOCO_APIKEY && '1' || '' }} + # TODO use ssh deployment key + - name: GitHub CLI extension + uses: actions/github-script@v8 + with: + github-token: ${{ secrets.CLI_GITHUB_TOKEN || secrets.GORELEASER_GITHUB_TOKEN }} + script: | + const mainRef = (await github.rest.git.getRef({ + owner: context.repo.owner, + repo: 'gh-act', + ref: 'heads/main', + })).data; + console.log(mainRef); + github.rest.git.createRef({ + owner: 'nektos', + repo: 'gh-act', + ref: context.ref, + sha: mainRef.object.sha, + }); + if: env.ENABLED + env: + ENABLED: ${{ (secrets.CLI_GITHUB_TOKEN || secrets.GORELEASER_GITHUB_TOKEN) && '1' || '' }} diff --git a/pkg/artifacts/server_test.go b/pkg/artifacts/server_test.go index 296c821b..7658ef1c 100644 --- a/pkg/artifacts/server_test.go +++ b/pkg/artifacts/server_test.go @@ -249,6 +249,9 @@ func TestArtifactFlow(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } + if _, ok := os.LookupEnv("NO_EXTERNAL_IP"); ok { + t.Skip("skipping test because QEMU is disabled") + } ctx := context.Background() diff --git a/pkg/common/git/git.go b/pkg/common/git/git.go index 9eedb3b3..8bf2f8fb 100644 --- a/pkg/common/git/git.go +++ b/pkg/common/git/git.go @@ -212,7 +212,8 @@ func matchesRegex(url string, matchers ...findStringSubmatcher) []string { return nil } -func findGitSlug(url string, githubInstance string) (string, string, error) { +// TODO deprecate and remove githubInstance parameter +func findGitSlug(url string, _ /* githubInstance */ string) (string, string, error) { if matches := matchesRegex(url, codeCommitHTTPRegex, codeCommitSSHRegex); matches != nil { return "CodeCommit", matches[2], nil } @@ -221,14 +222,13 @@ func findGitSlug(url string, githubInstance string) (string, string, error) { return "GitHub", fmt.Sprintf("%s/%s", matches[1], matches[2]), nil } - if githubInstance != "github.com" { - if matches := matchesRegex(url, - regexp.MustCompile(fmt.Sprintf(`^https?://%s/(.+)/(.+?)(?:.git)?$`, githubInstance)), - regexp.MustCompile(fmt.Sprintf(`%s[:/](.+)/(.+?)(?:.git)?$`, githubInstance)), - ); matches != nil { - return "GitHubEnterprise", fmt.Sprintf("%s/%s", matches[1], matches[2]), nil - } + if matches := matchesRegex(url, + regexp.MustCompile(`^https?://(?:[^/]+)/([^/]+)/([^/]+)(?:.git)?$`), + regexp.MustCompile(`([^/]+)[:/]([^/]+)/([^/]+)(?:.git)?$`), + ); matches != nil { + return "GitHubEnterprise", fmt.Sprintf("%s/%s", matches[1], matches[2]), nil } + return "", url, nil } diff --git a/pkg/common/git/git_test.go b/pkg/common/git/git_test.go index c6d70b50..fe1da240 100644 --- a/pkg/common/git/git_test.go +++ b/pkg/common/git/git_test.go @@ -34,6 +34,7 @@ func TestFindGitSlug(t *testing.T) { {"http://github.com/actions-oss/act-cli", "GitHub", "actions-oss/act-cli"}, {"git+ssh://git@github.com/owner/repo.git", "GitHub", "owner/repo"}, {"http://myotherrepo.com/act.git", "", "http://myotherrepo.com/act.git"}, + {"https://gitea.com/actions-oss/act-cli.git", "GitHubEnterprise", "actions-oss/act-cli.git"}, } for _, tt := range slugTests { diff --git a/pkg/container/docker_images_test.go b/pkg/container/docker_images_test.go index a6612832..8d506f53 100644 --- a/pkg/container/docker_images_test.go +++ b/pkg/container/docker_images_test.go @@ -3,6 +3,7 @@ package container import ( "context" "io" + "os" "testing" "github.com/docker/docker/api/types/image" @@ -51,6 +52,22 @@ func TestImageExistsLocally(t *testing.T) { imageDefaultArchExists, err := ImageExistsLocally(ctx, "node:16-buster-slim", "linux/amd64") assert.Nil(t, err) assert.Equal(t, true, imageDefaultArchExists) +} + +func TestImageExistsLocallyQemu(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test") + } + if _, ok := os.LookupEnv("NO_QEMU"); ok { + t.Skip("skipping test because QEMU is disabled") + } + + ctx := context.Background() + + // pull an image + cli, err := client.NewClientWithOpts(client.FromEnv) + assert.Nil(t, err) + cli.NegotiateAPIVersion(context.Background()) // Validate if another architecture platform can be pulled readerArm64, err := cli.ImagePull(ctx, "node:16-buster-slim", image.PullOptions{ diff --git a/pkg/runner/runner_test.go b/pkg/runner/runner_test.go index 1b7fe9ee..1fe6e21d 100644 --- a/pkg/runner/runner_test.go +++ b/pkg/runner/runner_test.go @@ -8,6 +8,7 @@ import ( "fmt" "io" "os" + "os/exec" "path" "path/filepath" "runtime" @@ -329,11 +330,16 @@ func TestRunEvent(t *testing.T) { // local remote action overrides {workdir, "local-remote-action-overrides", "push", "", platforms, secrets}, + } - // docker action on host executor - {workdir, "docker-action-host-env", "push", "", platforms, secrets}, - // docker service on host executor - {workdir, "nginx-service-container-host-mode", "push", "", platforms, secrets}, + if _, ok := os.LookupEnv("DOOD"); !ok { + // Does not work in Docker Out of Docker context, e.g. -v /var/run/docker.sock:/var/run/docker.sock + tables = append(tables, []TestJobFileInfo{ + // docker action on host executor + {workdir, "docker-action-host-env", "push", "", platforms, secrets}, + // docker service on host executor + {workdir, "nginx-service-container-host-mode", "push", "", platforms, secrets}, + }...) } for _, table := range tables { @@ -552,7 +558,6 @@ func TestRunEventHostEnvironment(t *testing.T) { tables = append(tables, []TestJobFileInfo{ // Shells {workdir, "shells/defaults", "push", "", platforms, secrets}, - {workdir, "shells/pwsh", "push", "", platforms, secrets}, {workdir, "shells/bash", "push", "", platforms, secrets}, {workdir, "shells/python", "push", "", platforms, secrets}, {workdir, "shells/sh", "push", "", platforms, secrets}, @@ -599,6 +604,13 @@ func TestRunEventHostEnvironment(t *testing.T) { {workdir, "evalenv", "push", "", platforms, secrets}, {workdir, "ensure-post-steps", "push", "Job 'second-post-step-should-fail' failed", platforms, secrets}, }...) + + // No pwsh on current default container image + if pwsh, err := exec.LookPath("pwsh"); err == nil && pwsh != "" { + tables = append(tables, []TestJobFileInfo{ + {workdir, "shells/pwsh", "push", "", platforms, secrets}, + }...) + } } if runtime.GOOS == "windows" { platforms := map[string]string{ @@ -692,6 +704,9 @@ func TestRunDifferentArchitecture(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } + if _, ok := os.LookupEnv("NO_QEMU"); ok { + t.Skip("skipping test because QEMU is disabled") + } tjfi := TestJobFileInfo{ workdir: workdir,